3 * Copyright (c) 2003 The Libav Project
5 * This file is part of Libav.
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/dict.h"
23 #include "libavutil/intfloat.h"
33 static const AVCodecTag flv_video_codec_ids
[] = {
34 { AV_CODEC_ID_FLV1
, FLV_CODECID_H263
},
35 { AV_CODEC_ID_FLASHSV
, FLV_CODECID_SCREEN
},
36 { AV_CODEC_ID_FLASHSV2
, FLV_CODECID_SCREEN2
},
37 { AV_CODEC_ID_VP6F
, FLV_CODECID_VP6
},
38 { AV_CODEC_ID_VP6A
, FLV_CODECID_VP6A
},
39 { AV_CODEC_ID_H264
, FLV_CODECID_H264
},
40 { AV_CODEC_ID_NONE
, 0 }
43 static const AVCodecTag flv_audio_codec_ids
[] = {
44 { AV_CODEC_ID_MP3
, FLV_CODECID_MP3
>> FLV_AUDIO_CODECID_OFFSET
},
45 { AV_CODEC_ID_PCM_U8
, FLV_CODECID_PCM
>> FLV_AUDIO_CODECID_OFFSET
},
46 { AV_CODEC_ID_PCM_S16BE
, FLV_CODECID_PCM
>> FLV_AUDIO_CODECID_OFFSET
},
47 { AV_CODEC_ID_PCM_S16LE
, FLV_CODECID_PCM_LE
>> FLV_AUDIO_CODECID_OFFSET
},
48 { AV_CODEC_ID_ADPCM_SWF
, FLV_CODECID_ADPCM
>> FLV_AUDIO_CODECID_OFFSET
},
49 { AV_CODEC_ID_AAC
, FLV_CODECID_AAC
>> FLV_AUDIO_CODECID_OFFSET
},
50 { AV_CODEC_ID_NELLYMOSER
, FLV_CODECID_NELLYMOSER
>> FLV_AUDIO_CODECID_OFFSET
},
51 { AV_CODEC_ID_PCM_MULAW
, FLV_CODECID_PCM_MULAW
>> FLV_AUDIO_CODECID_OFFSET
},
52 { AV_CODEC_ID_PCM_ALAW
, FLV_CODECID_PCM_ALAW
>> FLV_AUDIO_CODECID_OFFSET
},
53 { AV_CODEC_ID_SPEEX
, FLV_CODECID_SPEEX
>> FLV_AUDIO_CODECID_OFFSET
},
54 { AV_CODEC_ID_NONE
, 0 }
57 typedef struct FLVContext
{
59 int64_t duration_offset
;
60 int64_t filesize_offset
;
62 int64_t delay
; ///< first dts delay (needed for AVC & Speex)
64 AVCodecContext
*audio_enc
;
65 AVCodecContext
*video_enc
;
67 AVCodecContext
*data_enc
;
70 typedef struct FLVStreamContext
{
71 int64_t last_ts
; ///< last timestamp for each stream
74 static int get_audio_flags(AVFormatContext
*s
, AVCodecContext
*enc
)
76 int flags
= (enc
->bits_per_coded_sample
== 16) ? FLV_SAMPLESSIZE_16BIT
77 : FLV_SAMPLESSIZE_8BIT
;
79 if (enc
->codec_id
== AV_CODEC_ID_AAC
) // specs force these parameters
80 return FLV_CODECID_AAC
| FLV_SAMPLERATE_44100HZ
|
81 FLV_SAMPLESSIZE_16BIT
| FLV_STEREO
;
82 else if (enc
->codec_id
== AV_CODEC_ID_SPEEX
) {
83 if (enc
->sample_rate
!= 16000) {
84 av_log(s
, AV_LOG_ERROR
,
85 "flv only supports wideband (16kHz) Speex audio\n");
88 if (enc
->channels
!= 1) {
89 av_log(s
, AV_LOG_ERROR
, "flv only supports mono Speex audio\n");
92 return FLV_CODECID_SPEEX
| FLV_SAMPLERATE_11025HZ
| FLV_SAMPLESSIZE_16BIT
;
94 switch (enc
->sample_rate
) {
96 flags
|= FLV_SAMPLERATE_44100HZ
;
99 flags
|= FLV_SAMPLERATE_22050HZ
;
102 flags
|= FLV_SAMPLERATE_11025HZ
;
104 case 16000: // nellymoser only
105 case 8000: // nellymoser only
106 case 5512: // not MP3
107 if (enc
->codec_id
!= AV_CODEC_ID_MP3
) {
108 flags
|= FLV_SAMPLERATE_SPECIAL
;
112 av_log(s
, AV_LOG_ERROR
,
113 "flv does not support that sample rate, "
114 "choose from (44100, 22050, 11025).\n");
119 if (enc
->channels
> 1)
122 switch (enc
->codec_id
) {
123 case AV_CODEC_ID_MP3
:
124 flags
|= FLV_CODECID_MP3
| FLV_SAMPLESSIZE_16BIT
;
126 case AV_CODEC_ID_PCM_U8
:
127 flags
|= FLV_CODECID_PCM
| FLV_SAMPLESSIZE_8BIT
;
129 case AV_CODEC_ID_PCM_S16BE
:
130 flags
|= FLV_CODECID_PCM
| FLV_SAMPLESSIZE_16BIT
;
132 case AV_CODEC_ID_PCM_S16LE
:
133 flags
|= FLV_CODECID_PCM_LE
| FLV_SAMPLESSIZE_16BIT
;
135 case AV_CODEC_ID_ADPCM_SWF
:
136 flags
|= FLV_CODECID_ADPCM
| FLV_SAMPLESSIZE_16BIT
;
138 case AV_CODEC_ID_NELLYMOSER
:
139 if (enc
->sample_rate
== 8000)
140 flags
|= FLV_CODECID_NELLYMOSER_8KHZ_MONO
| FLV_SAMPLESSIZE_16BIT
;
141 else if (enc
->sample_rate
== 16000)
142 flags
|= FLV_CODECID_NELLYMOSER_16KHZ_MONO
| FLV_SAMPLESSIZE_16BIT
;
144 flags
|= FLV_CODECID_NELLYMOSER
| FLV_SAMPLESSIZE_16BIT
;
146 case AV_CODEC_ID_PCM_MULAW
:
147 flags
= FLV_CODECID_PCM_MULAW
| FLV_SAMPLERATE_SPECIAL
| FLV_SAMPLESSIZE_16BIT
;
149 case AV_CODEC_ID_PCM_ALAW
:
150 flags
= FLV_CODECID_PCM_ALAW
| FLV_SAMPLERATE_SPECIAL
| FLV_SAMPLESSIZE_16BIT
;
153 flags
|= enc
->codec_tag
<< 4;
156 av_log(s
, AV_LOG_ERROR
, "codec not compatible with flv\n");
163 static void put_amf_string(AVIOContext
*pb
, const char *str
)
165 size_t len
= strlen(str
);
167 avio_write(pb
, str
, len
);
170 static void put_avc_eos_tag(AVIOContext
*pb
, unsigned ts
)
172 avio_w8(pb
, FLV_TAG_TYPE_VIDEO
);
173 avio_wb24(pb
, 5); /* Tag Data Size */
174 avio_wb24(pb
, ts
); /* lower 24 bits of timestamp in ms */
175 avio_w8(pb
, (ts
>> 24) & 0x7F); /* MSB of ts in ms */
176 avio_wb24(pb
, 0); /* StreamId = 0 */
177 avio_w8(pb
, 23); /* ub[4] FrameType = 1, ub[4] CodecId = 7 */
178 avio_w8(pb
, 2); /* AVC end of sequence */
179 avio_wb24(pb
, 0); /* Always 0 for AVC EOS. */
180 avio_wb32(pb
, 16); /* Size of FLV tag */
183 static void put_amf_double(AVIOContext
*pb
, double d
)
185 avio_w8(pb
, AMF_DATA_TYPE_NUMBER
);
186 avio_wb64(pb
, av_double2int(d
));
189 static void put_amf_bool(AVIOContext
*pb
, int b
)
191 avio_w8(pb
, AMF_DATA_TYPE_BOOL
);
195 static void write_metadata(AVFormatContext
*s
, unsigned int ts
)
197 AVIOContext
*pb
= s
->pb
;
198 FLVContext
*flv
= s
->priv_data
;
199 int metadata_count
= 0;
200 int64_t metadata_size_pos
, data_size
, metadata_count_pos
;
201 AVDictionaryEntry
*tag
= NULL
;
204 avio_w8(pb
, 18); // tag type META
205 metadata_size_pos
= avio_tell(pb
);
206 avio_wb24(pb
, 0); // size of data part (sum of all parts below)
207 avio_wb24(pb
, ts
); // timestamp
208 avio_wb32(pb
, 0); // reserved
210 /* now data of data_size size */
212 /* first event name as a string */
213 avio_w8(pb
, AMF_DATA_TYPE_STRING
);
214 put_amf_string(pb
, "onMetaData"); // 12 bytes
216 /* mixed array (hash) with size and string/type/data tuples */
217 avio_w8(pb
, AMF_DATA_TYPE_MIXEDARRAY
);
218 metadata_count_pos
= avio_tell(pb
);
219 metadata_count
= 4 * !!flv
->video_enc
+
220 5 * !!flv
->audio_enc
+
221 1 * !!flv
->data_enc
+
222 2; // +2 for duration and file size
224 avio_wb32(pb
, metadata_count
);
226 put_amf_string(pb
, "duration");
227 flv
->duration_offset
= avio_tell(pb
);
229 // fill in the guessed duration, it'll be corrected later if incorrect
230 put_amf_double(pb
, s
->duration
/ AV_TIME_BASE
);
232 if (flv
->video_enc
) {
233 put_amf_string(pb
, "width");
234 put_amf_double(pb
, flv
->video_enc
->width
);
236 put_amf_string(pb
, "height");
237 put_amf_double(pb
, flv
->video_enc
->height
);
239 put_amf_string(pb
, "videodatarate");
240 put_amf_double(pb
, flv
->video_enc
->bit_rate
/ 1024.0);
242 if (flv
->framerate
!= 0.0) {
243 put_amf_string(pb
, "framerate");
244 put_amf_double(pb
, flv
->framerate
);
248 put_amf_string(pb
, "videocodecid");
249 put_amf_double(pb
, flv
->video_enc
->codec_tag
);
252 if (flv
->audio_enc
) {
253 put_amf_string(pb
, "audiodatarate");
254 put_amf_double(pb
, flv
->audio_enc
->bit_rate
/ 1024.0);
256 put_amf_string(pb
, "audiosamplerate");
257 put_amf_double(pb
, flv
->audio_enc
->sample_rate
);
259 put_amf_string(pb
, "audiosamplesize");
260 put_amf_double(pb
, flv
->audio_enc
->codec_id
== AV_CODEC_ID_PCM_U8 ?
8 : 16);
262 put_amf_string(pb
, "stereo");
263 put_amf_bool(pb
, flv
->audio_enc
->channels
== 2);
265 put_amf_string(pb
, "audiocodecid");
266 put_amf_double(pb
, flv
->audio_enc
->codec_tag
);
270 put_amf_string(pb
, "datastream");
271 put_amf_double(pb
, 0.0);
274 while ((tag
= av_dict_get(s
->metadata
, "", tag
, AV_DICT_IGNORE_SUFFIX
))) {
275 put_amf_string(pb
, tag
->key
);
276 avio_w8(pb
, AMF_DATA_TYPE_STRING
);
277 put_amf_string(pb
, tag
->value
);
281 put_amf_string(pb
, "filesize");
282 flv
->filesize_offset
= avio_tell(pb
);
283 put_amf_double(pb
, 0); // delayed write
285 put_amf_string(pb
, "");
286 avio_w8(pb
, AMF_END_OF_OBJECT
);
288 /* write total size of tag */
289 data_size
= avio_tell(pb
) - metadata_size_pos
- 10;
291 avio_seek(pb
, metadata_count_pos
, SEEK_SET
);
292 avio_wb32(pb
, metadata_count
);
294 avio_seek(pb
, metadata_size_pos
, SEEK_SET
);
295 avio_wb24(pb
, data_size
);
296 avio_skip(pb
, data_size
+ 10 - 3);
297 avio_wb32(pb
, data_size
+ 11);
300 static int unsupported_codec(AVFormatContext
*s
,
301 const char* type
, int codec_id
)
303 const AVCodecDescriptor
*desc
= avcodec_descriptor_get(codec_id
);
304 av_log(s
, AV_LOG_ERROR
,
305 "%s codec %s not compatible with flv\n",
307 desc ? desc
->name
: "unknown");
308 return AVERROR(ENOSYS
);
311 static int flv_write_header(AVFormatContext
*s
)
314 AVIOContext
*pb
= s
->pb
;
315 FLVContext
*flv
= s
->priv_data
;
318 for (i
= 0; i
< s
->nb_streams
; i
++) {
319 AVCodecContext
*enc
= s
->streams
[i
]->codec
;
320 FLVStreamContext
*sc
;
321 switch (enc
->codec_type
) {
322 case AVMEDIA_TYPE_VIDEO
:
323 if (s
->streams
[i
]->avg_frame_rate
.den
&&
324 s
->streams
[i
]->avg_frame_rate
.num
) {
325 flv
->framerate
= av_q2d(s
->streams
[i
]->avg_frame_rate
);
327 if (flv
->video_enc
) {
328 av_log(s
, AV_LOG_ERROR
,
329 "at most one video stream is supported in flv\n");
330 return AVERROR(EINVAL
);
332 flv
->video_enc
= enc
;
333 if (!ff_codec_get_tag(flv_video_codec_ids
, enc
->codec_id
))
334 return unsupported_codec(s
, "Video", enc
->codec_id
);
336 case AVMEDIA_TYPE_AUDIO
:
337 if (flv
->audio_enc
) {
338 av_log(s
, AV_LOG_ERROR
,
339 "at most one audio stream is supported in flv\n");
340 return AVERROR(EINVAL
);
342 flv
->audio_enc
= enc
;
343 if (get_audio_flags(s
, enc
) < 0)
344 return unsupported_codec(s
, "Audio", enc
->codec_id
);
346 case AVMEDIA_TYPE_DATA
:
347 if (enc
->codec_id
!= AV_CODEC_ID_TEXT
)
348 return unsupported_codec(s
, "Data", enc
->codec_id
);
352 av_log(s
, AV_LOG_ERROR
, "codec not compatible with flv\n");
355 avpriv_set_pts_info(s
->streams
[i
], 32, 1, 1000); /* 32 bit pts in ms */
357 sc
= av_mallocz(sizeof(FLVStreamContext
));
359 return AVERROR(ENOMEM
);
360 s
->streams
[i
]->priv_data
= sc
;
364 flv
->delay
= AV_NOPTS_VALUE
;
366 avio_write(pb
, "FLV", 3);
368 avio_w8(pb
, FLV_HEADER_FLAG_HASAUDIO
* !!flv
->audio_enc
+
369 FLV_HEADER_FLAG_HASVIDEO
* !!flv
->video_enc
);
373 for (i
= 0; i
< s
->nb_streams
; i
++)
374 if (s
->streams
[i
]->codec
->codec_tag
== 5) {
375 avio_w8(pb
, 8); // message type
376 avio_wb24(pb
, 0); // include flags
377 avio_wb24(pb
, 0); // time stamp
378 avio_wb32(pb
, 0); // reserved
379 avio_wb32(pb
, 11); // size
383 write_metadata(s
, 0);
385 for (i
= 0; i
< s
->nb_streams
; i
++) {
386 AVCodecContext
*enc
= s
->streams
[i
]->codec
;
387 if (enc
->codec_id
== AV_CODEC_ID_AAC
|| enc
->codec_id
== AV_CODEC_ID_H264
) {
389 avio_w8(pb
, enc
->codec_type
== AVMEDIA_TYPE_VIDEO ?
390 FLV_TAG_TYPE_VIDEO
: FLV_TAG_TYPE_AUDIO
);
391 avio_wb24(pb
, 0); // size patched later
392 avio_wb24(pb
, 0); // ts
393 avio_w8(pb
, 0); // ts ext
394 avio_wb24(pb
, 0); // streamid
396 if (enc
->codec_id
== AV_CODEC_ID_AAC
) {
397 avio_w8(pb
, get_audio_flags(s
, enc
));
398 avio_w8(pb
, 0); // AAC sequence header
399 avio_write(pb
, enc
->extradata
, enc
->extradata_size
);
401 avio_w8(pb
, enc
->codec_tag
| FLV_FRAME_KEY
); // flags
402 avio_w8(pb
, 0); // AVC sequence header
403 avio_wb24(pb
, 0); // composition time
404 ff_isom_write_avcc(pb
, enc
->extradata
, enc
->extradata_size
);
406 data_size
= avio_tell(pb
) - pos
;
407 avio_seek(pb
, -data_size
- 10, SEEK_CUR
);
408 avio_wb24(pb
, data_size
);
409 avio_skip(pb
, data_size
+ 10 - 3);
410 avio_wb32(pb
, data_size
+ 11); // previous tag size
417 static int flv_write_trailer(AVFormatContext
*s
)
421 AVIOContext
*pb
= s
->pb
;
422 FLVContext
*flv
= s
->priv_data
;
426 for (i
= 0; i
< s
->nb_streams
; i
++) {
427 AVCodecContext
*enc
= s
->streams
[i
]->codec
;
428 FLVStreamContext
*sc
= s
->streams
[i
]->priv_data
;
429 if (enc
->codec_type
== AVMEDIA_TYPE_VIDEO
&&
430 enc
->codec_id
== AV_CODEC_ID_H264
)
431 put_avc_eos_tag(pb
, sc
->last_ts
);
434 file_size
= avio_tell(pb
);
436 /* update information */
437 if (avio_seek(pb
, flv
->duration_offset
, SEEK_SET
) < 0)
438 av_log(s
, AV_LOG_WARNING
, "Failed to update header with correct duration.\n");
440 put_amf_double(pb
, flv
->duration
/ (double)1000);
441 if (avio_seek(pb
, flv
->filesize_offset
, SEEK_SET
) < 0)
442 av_log(s
, AV_LOG_WARNING
, "Failed to update header with correct filesize.\n");
444 put_amf_double(pb
, file_size
);
446 avio_seek(pb
, file_size
, SEEK_SET
);
450 static int flv_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
452 AVIOContext
*pb
= s
->pb
;
453 AVCodecContext
*enc
= s
->streams
[pkt
->stream_index
]->codec
;
454 FLVContext
*flv
= s
->priv_data
;
455 FLVStreamContext
*sc
= s
->streams
[pkt
->stream_index
]->priv_data
;
457 int size
= pkt
->size
;
458 uint8_t *data
= NULL
;
459 int flags
= 0, flags_size
;
461 if (enc
->codec_id
== AV_CODEC_ID_VP6F
|| enc
->codec_id
== AV_CODEC_ID_VP6A
||
462 enc
->codec_id
== AV_CODEC_ID_AAC
)
464 else if (enc
->codec_id
== AV_CODEC_ID_H264
)
469 if (flv
->delay
== AV_NOPTS_VALUE
)
470 flv
->delay
= -pkt
->dts
;
472 if (pkt
->dts
< -flv
->delay
) {
473 av_log(s
, AV_LOG_WARNING
,
474 "Packets are not in the proper order with respect to DTS\n");
475 return AVERROR(EINVAL
);
478 ts
= pkt
->dts
+ flv
->delay
; // add delay to force positive dts
480 if (s
->event_flags
& AVSTREAM_EVENT_FLAG_METADATA_UPDATED
) {
481 write_metadata(s
, ts
);
482 s
->event_flags
&= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED
;
485 switch (enc
->codec_type
) {
486 case AVMEDIA_TYPE_VIDEO
:
487 avio_w8(pb
, FLV_TAG_TYPE_VIDEO
);
489 flags
= ff_codec_get_tag(flv_video_codec_ids
, enc
->codec_id
);
491 flags
|= pkt
->flags
& AV_PKT_FLAG_KEY ? FLV_FRAME_KEY
: FLV_FRAME_INTER
;
493 case AVMEDIA_TYPE_AUDIO
:
494 flags
= get_audio_flags(s
, enc
);
498 avio_w8(pb
, FLV_TAG_TYPE_AUDIO
);
500 case AVMEDIA_TYPE_DATA
:
501 avio_w8(pb
, FLV_TAG_TYPE_META
);
504 return AVERROR(EINVAL
);
507 if (enc
->codec_id
== AV_CODEC_ID_H264
)
508 /* check if extradata looks like MP4 */
509 if (enc
->extradata_size
> 0 && *(uint8_t*)enc
->extradata
!= 1)
510 if (ff_avc_parse_nal_units_buf(pkt
->data
, &data
, &size
) < 0)
513 /* check Speex packet duration */
514 if (enc
->codec_id
== AV_CODEC_ID_SPEEX
&& ts
- sc
->last_ts
> 160)
515 av_log(s
, AV_LOG_WARNING
, "Warning: Speex stream has more than "
516 "8 frames per packet. Adobe Flash "
517 "Player cannot handle this!\n");
519 if (sc
->last_ts
< ts
)
522 avio_wb24(pb
, size
+ flags_size
);
524 avio_w8(pb
, (ts
>> 24) & 0x7F); // timestamps are 32 bits _signed_
525 avio_wb24(pb
, flv
->reserved
);
527 if (enc
->codec_type
== AVMEDIA_TYPE_DATA
) {
529 int64_t metadata_size_pos
= avio_tell(pb
);
530 avio_w8(pb
, AMF_DATA_TYPE_STRING
);
531 put_amf_string(pb
, "onTextData");
532 avio_w8(pb
, AMF_DATA_TYPE_MIXEDARRAY
);
534 put_amf_string(pb
, "type");
535 avio_w8(pb
, AMF_DATA_TYPE_STRING
);
536 put_amf_string(pb
, "Text");
537 put_amf_string(pb
, "text");
538 avio_w8(pb
, AMF_DATA_TYPE_STRING
);
539 put_amf_string(pb
, pkt
->data
);
540 put_amf_string(pb
, "");
541 avio_w8(pb
, AMF_END_OF_OBJECT
);
542 /* write total size of tag */
543 data_size
= avio_tell(pb
) - metadata_size_pos
;
544 avio_seek(pb
, metadata_size_pos
- 10, SEEK_SET
);
545 avio_wb24(pb
, data_size
);
546 avio_seek(pb
, data_size
+ 10 - 3, SEEK_CUR
);
547 avio_wb32(pb
, data_size
+ 11);
550 if (enc
->codec_id
== AV_CODEC_ID_VP6F
|| enc
->codec_id
== AV_CODEC_ID_VP6A
) {
551 if (enc
->extradata_size
)
552 avio_w8(pb
, enc
->extradata
[0]);
554 avio_w8(pb
, ((FFALIGN(enc
->width
, 16) - enc
->width
) << 4) |
555 (FFALIGN(enc
->height
, 16) - enc
->height
));
556 } else if (enc
->codec_id
== AV_CODEC_ID_AAC
)
557 avio_w8(pb
, 1); // AAC raw
558 else if (enc
->codec_id
== AV_CODEC_ID_H264
) {
559 avio_w8(pb
, 1); // AVC NALU
560 avio_wb24(pb
, pkt
->pts
- pkt
->dts
);
563 avio_write(pb
, data ? data
: pkt
->data
, size
);
565 avio_wb32(pb
, size
+ flags_size
+ 11); // previous tag size
566 flv
->duration
= FFMAX(flv
->duration
,
567 pkt
->pts
+ flv
->delay
+ pkt
->duration
);
575 AVOutputFormat ff_flv_muxer
= {
577 .long_name
= NULL_IF_CONFIG_SMALL("FLV (Flash Video)"),
578 .mime_type
= "video/x-flv",
580 .priv_data_size
= sizeof(FLVContext
),
581 .audio_codec
= CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3
: AV_CODEC_ID_ADPCM_SWF
,
582 .video_codec
= AV_CODEC_ID_FLV1
,
583 .write_header
= flv_write_header
,
584 .write_packet
= flv_write_packet
,
585 .write_trailer
= flv_write_trailer
,
586 .codec_tag
= (const AVCodecTag
* const []) {
587 flv_video_codec_ids
, flv_audio_codec_ids
, 0
589 .flags
= AVFMT_GLOBALHEADER
| AVFMT_VARIABLE_FPS
|