Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
52867 views
1
/*****************************************************************************
2
* flv.c: flv muxer
3
*****************************************************************************
4
* Copyright (C) 2009-2016 x264 project
5
*
6
* Authors: Kieran Kunhya <[email protected]>
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
21
*
22
* This program is also available under a commercial proprietary license.
23
* For more information, contact us at [email protected].
24
*****************************************************************************/
25
26
#include "output.h"
27
#include "flv_bytestream.h"
28
29
#define CHECK(x)\
30
do {\
31
if( (x) < 0 )\
32
return -1;\
33
} while( 0 )
34
35
typedef struct
36
{
37
flv_buffer *c;
38
39
uint8_t *sei;
40
int sei_len;
41
42
int64_t i_fps_num;
43
int64_t i_fps_den;
44
int64_t i_framenum;
45
46
uint64_t i_framerate_pos;
47
uint64_t i_duration_pos;
48
uint64_t i_filesize_pos;
49
uint64_t i_bitrate_pos;
50
51
uint8_t b_write_length;
52
int64_t i_prev_dts;
53
int64_t i_prev_cts;
54
int64_t i_delay_time;
55
int64_t i_init_delta;
56
int i_delay_frames;
57
58
double d_timebase;
59
int b_vfr_input;
60
int b_dts_compress;
61
62
unsigned start;
63
} flv_hnd_t;
64
65
static int write_header( flv_buffer *c )
66
{
67
flv_put_tag( c, "FLV" ); // Signature
68
flv_put_byte( c, 1 ); // Version
69
flv_put_byte( c, 1 ); // Video Only
70
flv_put_be32( c, 9 ); // DataOffset
71
flv_put_be32( c, 0 ); // PreviousTagSize0
72
73
return flv_flush_data( c );
74
}
75
76
static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt )
77
{
78
flv_hnd_t *p_flv = calloc( 1, sizeof(flv_hnd_t) );
79
if( p_flv )
80
{
81
flv_buffer *c = flv_create_writer( psz_filename );
82
if( c )
83
{
84
if( !write_header( c ) )
85
{
86
p_flv->c = c;
87
p_flv->b_dts_compress = opt->use_dts_compress;
88
*p_handle = p_flv;
89
return 0;
90
}
91
92
fclose( c->fp );
93
free( c->data );
94
free( c );
95
}
96
free( p_flv );
97
}
98
99
*p_handle = NULL;
100
return -1;
101
}
102
103
static int set_param( hnd_t handle, x264_param_t *p_param )
104
{
105
flv_hnd_t *p_flv = handle;
106
flv_buffer *c = p_flv->c;
107
108
flv_put_byte( c, FLV_TAG_TYPE_META ); // Tag Type "script data"
109
110
int start = c->d_cur;
111
flv_put_be24( c, 0 ); // data length
112
flv_put_be24( c, 0 ); // timestamp
113
flv_put_be32( c, 0 ); // reserved
114
115
flv_put_byte( c, AMF_DATA_TYPE_STRING );
116
flv_put_amf_string( c, "onMetaData" );
117
118
flv_put_byte( c, AMF_DATA_TYPE_MIXEDARRAY );
119
flv_put_be32( c, 7 );
120
121
flv_put_amf_string( c, "width" );
122
flv_put_amf_double( c, p_param->i_width );
123
124
flv_put_amf_string( c, "height" );
125
flv_put_amf_double( c, p_param->i_height );
126
127
flv_put_amf_string( c, "framerate" );
128
129
if( !p_param->b_vfr_input )
130
flv_put_amf_double( c, (double)p_param->i_fps_num / p_param->i_fps_den );
131
else
132
{
133
p_flv->i_framerate_pos = c->d_cur + c->d_total + 1;
134
flv_put_amf_double( c, 0 ); // written at end of encoding
135
}
136
137
flv_put_amf_string( c, "videocodecid" );
138
flv_put_amf_double( c, FLV_CODECID_H264 );
139
140
flv_put_amf_string( c, "duration" );
141
p_flv->i_duration_pos = c->d_cur + c->d_total + 1;
142
flv_put_amf_double( c, 0 ); // written at end of encoding
143
144
flv_put_amf_string( c, "filesize" );
145
p_flv->i_filesize_pos = c->d_cur + c->d_total + 1;
146
flv_put_amf_double( c, 0 ); // written at end of encoding
147
148
flv_put_amf_string( c, "videodatarate" );
149
p_flv->i_bitrate_pos = c->d_cur + c->d_total + 1;
150
flv_put_amf_double( c, 0 ); // written at end of encoding
151
152
flv_put_amf_string( c, "" );
153
flv_put_byte( c, AMF_END_OF_OBJECT );
154
155
unsigned length = c->d_cur - start;
156
flv_rewrite_amf_be24( c, length - 10, start );
157
158
flv_put_be32( c, length + 1 ); // tag length
159
160
p_flv->i_fps_num = p_param->i_fps_num;
161
p_flv->i_fps_den = p_param->i_fps_den;
162
p_flv->d_timebase = (double)p_param->i_timebase_num / p_param->i_timebase_den;
163
p_flv->b_vfr_input = p_param->b_vfr_input;
164
p_flv->i_delay_frames = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0;
165
166
return 0;
167
}
168
169
static int write_headers( hnd_t handle, x264_nal_t *p_nal )
170
{
171
flv_hnd_t *p_flv = handle;
172
flv_buffer *c = p_flv->c;
173
174
int sps_size = p_nal[0].i_payload;
175
int pps_size = p_nal[1].i_payload;
176
int sei_size = p_nal[2].i_payload;
177
178
// SEI
179
/* It is within the spec to write this as-is but for
180
* mplayer/ffmpeg playback this is deferred until before the first frame */
181
182
p_flv->sei = malloc( sei_size );
183
if( !p_flv->sei )
184
return -1;
185
p_flv->sei_len = sei_size;
186
187
memcpy( p_flv->sei, p_nal[2].p_payload, sei_size );
188
189
// SPS
190
uint8_t *sps = p_nal[0].p_payload + 4;
191
192
flv_put_byte( c, FLV_TAG_TYPE_VIDEO );
193
flv_put_be24( c, 0 ); // rewrite later
194
flv_put_be24( c, 0 ); // timestamp
195
flv_put_byte( c, 0 ); // timestamp extended
196
flv_put_be24( c, 0 ); // StreamID - Always 0
197
p_flv->start = c->d_cur; // needed for overwriting length
198
199
flv_put_byte( c, 7 | FLV_FRAME_KEY ); // Frametype and CodecID
200
flv_put_byte( c, 0 ); // AVC sequence header
201
flv_put_be24( c, 0 ); // composition time
202
203
flv_put_byte( c, 1 ); // version
204
flv_put_byte( c, sps[1] ); // profile
205
flv_put_byte( c, sps[2] ); // profile
206
flv_put_byte( c, sps[3] ); // level
207
flv_put_byte( c, 0xff ); // 6 bits reserved (111111) + 2 bits nal size length - 1 (11)
208
flv_put_byte( c, 0xe1 ); // 3 bits reserved (111) + 5 bits number of sps (00001)
209
210
flv_put_be16( c, sps_size - 4 );
211
flv_append_data( c, sps, sps_size - 4 );
212
213
// PPS
214
flv_put_byte( c, 1 ); // number of pps
215
flv_put_be16( c, pps_size - 4 );
216
flv_append_data( c, p_nal[1].p_payload + 4, pps_size - 4 );
217
218
// rewrite data length info
219
unsigned length = c->d_cur - p_flv->start;
220
flv_rewrite_amf_be24( c, length, p_flv->start - 10 );
221
flv_put_be32( c, length + 11 ); // Last tag size
222
CHECK( flv_flush_data( c ) );
223
224
return sei_size + sps_size + pps_size;
225
}
226
227
static int write_frame( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture )
228
{
229
flv_hnd_t *p_flv = handle;
230
flv_buffer *c = p_flv->c;
231
232
#define convert_timebase_ms( timestamp, timebase ) (int64_t)((timestamp) * (timebase) * 1000 + 0.5)
233
234
if( !p_flv->i_framenum )
235
{
236
p_flv->i_delay_time = p_picture->i_dts * -1;
237
if( !p_flv->b_dts_compress && p_flv->i_delay_time )
238
x264_cli_log( "flv", X264_LOG_INFO, "initial delay %"PRId64" ms\n",
239
convert_timebase_ms( p_picture->i_pts + p_flv->i_delay_time, p_flv->d_timebase ) );
240
}
241
242
int64_t dts;
243
int64_t cts;
244
int64_t offset;
245
246
if( p_flv->b_dts_compress )
247
{
248
if( p_flv->i_framenum == 1 )
249
p_flv->i_init_delta = convert_timebase_ms( p_picture->i_dts + p_flv->i_delay_time, p_flv->d_timebase );
250
dts = p_flv->i_framenum > p_flv->i_delay_frames
251
? convert_timebase_ms( p_picture->i_dts, p_flv->d_timebase )
252
: p_flv->i_framenum * p_flv->i_init_delta / (p_flv->i_delay_frames + 1);
253
cts = convert_timebase_ms( p_picture->i_pts, p_flv->d_timebase );
254
}
255
else
256
{
257
dts = convert_timebase_ms( p_picture->i_dts + p_flv->i_delay_time, p_flv->d_timebase );
258
cts = convert_timebase_ms( p_picture->i_pts + p_flv->i_delay_time, p_flv->d_timebase );
259
}
260
offset = cts - dts;
261
262
if( p_flv->i_framenum )
263
{
264
if( p_flv->i_prev_dts == dts )
265
x264_cli_log( "flv", X264_LOG_WARNING, "duplicate DTS %"PRId64" generated by rounding\n"
266
" decoding framerate cannot exceed 1000fps\n", dts );
267
if( p_flv->i_prev_cts == cts )
268
x264_cli_log( "flv", X264_LOG_WARNING, "duplicate CTS %"PRId64" generated by rounding\n"
269
" composition framerate cannot exceed 1000fps\n", cts );
270
}
271
p_flv->i_prev_dts = dts;
272
p_flv->i_prev_cts = cts;
273
274
// A new frame - write packet header
275
flv_put_byte( c, FLV_TAG_TYPE_VIDEO );
276
flv_put_be24( c, 0 ); // calculated later
277
flv_put_be24( c, dts );
278
flv_put_byte( c, dts >> 24 );
279
flv_put_be24( c, 0 );
280
281
p_flv->start = c->d_cur;
282
flv_put_byte( c, p_picture->b_keyframe ? FLV_FRAME_KEY : FLV_FRAME_INTER );
283
flv_put_byte( c, 1 ); // AVC NALU
284
flv_put_be24( c, offset );
285
286
if( p_flv->sei )
287
{
288
flv_append_data( c, p_flv->sei, p_flv->sei_len );
289
free( p_flv->sei );
290
p_flv->sei = NULL;
291
}
292
flv_append_data( c, p_nalu, i_size );
293
294
unsigned length = c->d_cur - p_flv->start;
295
flv_rewrite_amf_be24( c, length, p_flv->start - 10 );
296
flv_put_be32( c, 11 + length ); // Last tag size
297
CHECK( flv_flush_data( c ) );
298
299
p_flv->i_framenum++;
300
301
return i_size;
302
}
303
304
static int rewrite_amf_double( FILE *fp, uint64_t position, double value )
305
{
306
uint64_t x = endian_fix64( flv_dbl2int( value ) );
307
return !fseek( fp, position, SEEK_SET ) && fwrite( &x, 8, 1, fp ) == 1 ? 0 : -1;
308
}
309
310
#undef CHECK
311
#define CHECK(x)\
312
do {\
313
if( (x) < 0 )\
314
goto error;\
315
} while( 0 )
316
317
static int close_file( hnd_t handle, int64_t largest_pts, int64_t second_largest_pts )
318
{
319
int ret = -1;
320
flv_hnd_t *p_flv = handle;
321
flv_buffer *c = p_flv->c;
322
323
CHECK( flv_flush_data( c ) );
324
325
double total_duration = (2 * largest_pts - second_largest_pts) * p_flv->d_timebase;
326
327
if( x264_is_regular_file( c->fp ) && total_duration > 0 )
328
{
329
double framerate;
330
uint64_t filesize = ftell( c->fp );
331
332
if( p_flv->i_framerate_pos )
333
{
334
framerate = (double)p_flv->i_framenum / total_duration;
335
CHECK( rewrite_amf_double( c->fp, p_flv->i_framerate_pos, framerate ) );
336
}
337
338
CHECK( rewrite_amf_double( c->fp, p_flv->i_duration_pos, total_duration ) );
339
CHECK( rewrite_amf_double( c->fp, p_flv->i_filesize_pos, filesize ) );
340
CHECK( rewrite_amf_double( c->fp, p_flv->i_bitrate_pos, filesize * 8 / ( total_duration * 1000 ) ) );
341
}
342
ret = 0;
343
344
error:
345
fclose( c->fp );
346
free( c->data );
347
free( c );
348
free( p_flv );
349
350
return ret;
351
}
352
353
const cli_output_t flv_output = { open_file, set_param, write_headers, write_frame, close_file };
354
355