@ -20,43 +20,45 @@
*/
# include "libavutil/intreadwrite.h"
# include "libavutil/dict.h"
# include "libavutil/intfloat.h"
# include "libavutil/avassert.h"
# include "avc.h"
# include "avformat.h"
# include "flv.h"
# include "internal.h"
# include "avc.h"
# include "metadata.h"
# include "libavutil/dict.h"
# include "libavutil/avassert.h"
static const AVCodecTag flv_video_codec_ids [ ] = {
{ CODEC_ID_FLV1 , FLV_CODECID_H263 } ,
{ CODEC_ID_H263 , FLV_CODECID_REALH263 } ,
{ CODEC_ID_MPEG4 , FLV_CODECID_MPEG4 } ,
{ CODEC_ID_FLASHSV , FLV_CODECID_SCREEN } ,
{ CODEC_ID_FLASHSV2 , FLV_CODECID_SCREEN2 } ,
{ CODEC_ID_VP6F , FLV_CODECID_VP6 } ,
{ CODEC_ID_VP6 , FLV_CODECID_VP6 } ,
{ CODEC_ID_VP6A , FLV_CODECID_VP6A } ,
{ CODEC_ID_H264 , FLV_CODECID_H264 } ,
{ CODEC_ID_NONE , 0 }
{ CODEC_ID_FLV1 , FLV_CODECID_H263 } ,
{ CODEC_ID_H263 , FLV_CODECID_REALH263 } ,
{ CODEC_ID_MPEG4 , FLV_CODECID_MPEG4 } ,
{ CODEC_ID_FLASHSV , FLV_CODECID_SCREEN } ,
{ CODEC_ID_FLASHSV2 , FLV_CODECID_SCREEN2 } ,
{ CODEC_ID_VP6F , FLV_CODECID_VP6 } ,
{ CODEC_ID_VP6 , FLV_CODECID_VP6 } ,
{ CODEC_ID_VP6A , FLV_CODECID_VP6A } ,
{ CODEC_ID_H264 , FLV_CODECID_H264 } ,
{ CODEC_ID_NONE , 0 }
} ;
static const AVCodecTag flv_audio_codec_ids [ ] = {
{ CODEC_ID_MP3 , FLV_CODECID_MP3 > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_PCM_U8 , FLV_CODECID_PCM > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_PCM_S16BE , FLV_CODECID_PCM > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_PCM_S16LE , FLV_CODECID_PCM_LE > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_ADPCM_SWF , FLV_CODECID_ADPCM > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_AAC , FLV_CODECID_AAC > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_NELLYMOSER , FLV_CODECID_NELLYMOSER > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_SPEEX , FLV_CODECID_SPEEX > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_NONE , 0 }
{ CODEC_ID_MP3 , FLV_CODECID_MP3 > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_PCM_U8 , FLV_CODECID_PCM > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_PCM_S16BE , FLV_CODECID_PCM > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_PCM_S16LE , FLV_CODECID_PCM_LE > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_ADPCM_SWF , FLV_CODECID_ADPCM > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_AAC , FLV_CODECID_AAC > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_NELLYMOSER , FLV_CODECID_NELLYMOSER > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_PCM_MULAW , FLV_CODECID_PCM_MULAW > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_PCM_ALAW , FLV_CODECID_PCM_ALAW > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_SPEEX , FLV_CODECID_SPEEX > > FLV_AUDIO_CODECID_OFFSET } ,
{ CODEC_ID_NONE , 0 }
} ;
typedef struct FLVContext {
int reserved ;
int reserved ;
int64_t duration_offset ;
int64_t filesize_offset ;
int64_t duration ;
@ -69,13 +71,16 @@ typedef struct FLVStreamContext {
static int get_audio_flags ( AVFormatContext * s , AVCodecContext * enc )
{
int flags = ( enc - > bits_per_coded_sample = = 16 ) ? FLV_SAMPLESSIZE_16BIT : FLV_SAMPLESSIZE_8BIT ;
int flags = ( enc - > bits_per_coded_sample = = 16 ) ? FLV_SAMPLESSIZE_16BIT
: FLV_SAMPLESSIZE_8BIT ;
if ( enc - > codec_id = = CODEC_ID_AAC ) // specs force these parameters
return FLV_CODECID_AAC | FLV_SAMPLERATE_44100HZ | FLV_SAMPLESSIZE_16BIT | FLV_STEREO ;
return FLV_CODECID_AAC | FLV_SAMPLERATE_44100HZ |
FLV_SAMPLESSIZE_16BIT | FLV_STEREO ;
else if ( enc - > codec_id = = CODEC_ID_SPEEX ) {
if ( enc - > sample_rate ! = 16000 ) {
av_log ( s , AV_LOG_ERROR , " flv only supports wideband (16kHz) Speex audio \n " ) ;
av_log ( s , AV_LOG_ERROR ,
" flv only supports wideband (16kHz) Speex audio \n " ) ;
return - 1 ;
}
if ( enc - > channels ! = 1 ) {
@ -84,34 +89,35 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
}
return FLV_CODECID_SPEEX | FLV_SAMPLERATE_11025HZ | FLV_SAMPLESSIZE_16BIT ;
} else {
switch ( enc - > sample_rate ) {
case 44100 :
switch ( enc - > sample_rate ) {
case 44100 :
flags | = FLV_SAMPLERATE_44100HZ ;
break ;
case 22050 :
case 22050 :
flags | = FLV_SAMPLERATE_22050HZ ;
break ;
case 11025 :
case 11025 :
flags | = FLV_SAMPLERATE_11025HZ ;
break ;
case 16000 : //nellymoser only
case 8000 : //nellymoser only
case 5512 : //not mp 3
if ( enc - > codec_id ! = CODEC_ID_MP3 ) {
case 16000 : // nellymoser only
case 8000 : // nellymoser only
case 5512 : // not MP 3
if ( enc - > codec_id ! = CODEC_ID_MP3 ) {
flags | = FLV_SAMPLERATE_SPECIAL ;
break ;
}
default :
av_log ( s , AV_LOG_ERROR , " flv does not support that sample rate, choose from (44100, 22050, 11025). \n " ) ;
av_log ( s , AV_LOG_ERROR ,
" flv does not support that sample rate, "
" choose from (44100, 22050, 11025). \n " ) ;
return - 1 ;
}
}
}
if ( enc - > channels > 1 ) {
if ( enc - > channels > 1 )
flags | = FLV_STEREO ;
}
switch ( enc - > codec_id ) {
switch ( enc - > codec_id ) {
case CODEC_ID_MP3 :
flags | = FLV_CODECID_MP3 | FLV_SAMPLESSIZE_16BIT ;
break ;
@ -125,19 +131,24 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
flags | = FLV_CODECID_PCM_LE | FLV_SAMPLESSIZE_16BIT ;
break ;
case CODEC_ID_ADPCM_SWF :
flags | = FLV_CODECID_ADPCM | FLV_SAMPLESSIZE_16BIT ;
flags | = FLV_CODECID_ADPCM | FLV_SAMPLESSIZE_16BIT ;
break ;
case CODEC_ID_NELLYMOSER :
if ( enc - > sample_rate = = 8000 ) {
flags | = FLV_CODECID_NELLYMOSER_8KHZ_MONO | FLV_SAMPLESSIZE_16BIT ;
} else if ( enc - > sample_rate = = 16000 ) {
if ( enc - > sample_rate = = 8000 )
flags | = FLV_CODECID_NELLYMOSER_8KHZ_MONO | FLV_SAMPLESSIZE_16BIT ;
else if ( enc - > sample_rate = = 16000 )
flags | = FLV_CODECID_NELLYMOSER_16KHZ_MONO | FLV_SAMPLESSIZE_16BIT ;
} else {
flags | = FLV_CODECID_NELLYMOSER | FLV_SAMPLESSIZE_16BIT ;
}
else
flags | = FLV_CODECID_NELLYMOSER | FLV_SAMPLESSIZE_16BIT ;
break ;
case CODEC_ID_PCM_MULAW :
flags = FLV_CODECID_PCM_MULAW | FLV_SAMPLERATE_SPECIAL | FLV_SAMPLESSIZE_16BIT ;
break ;
case CODEC_ID_PCM_ALAW :
flags = FLV_CODECID_PCM_ALAW | FLV_SAMPLERATE_SPECIAL | FLV_SAMPLESSIZE_16BIT ;
break ;
case 0 :
flags | = enc - > codec_tag < < 4 ;
flags | = enc - > codec_tag < < 4 ;
break ;
default :
av_log ( s , AV_LOG_ERROR , " codec not compatible with flv \n " ) ;
@ -154,16 +165,17 @@ static void put_amf_string(AVIOContext *pb, const char *str)
avio_write ( pb , str , len ) ;
}
static void put_avc_eos_tag ( AVIOContext * pb , unsigned ts ) {
static void put_avc_eos_tag ( AVIOContext * pb , unsigned ts )
{
avio_w8 ( pb , FLV_TAG_TYPE_VIDEO ) ;
avio_wb24 ( pb , 5 ) ; /* Tag Data Size */
avio_wb24 ( pb , ts ) ; /* lower 24 bits of timestamp in ms*/
avio_w8 ( pb , ( ts > > 24 ) & 0x7F ) ; /* MSB of ts in ms*/
avio_wb24 ( pb , 0 ) ; /* StreamId = 0 */
avio_w8 ( pb , 23 ) ; /* ub[4] FrameType = 1, ub[4] CodecId = 7 */
avio_w8 ( pb , 2 ) ; /* AVC end of sequence */
avio_wb24 ( pb , 0 ) ; /* Always 0 for AVC EOS. */
avio_wb32 ( pb , 16 ) ; /* Size of FLV tag */
avio_wb24 ( pb , 5 ) ; /* Tag Data Size */
avio_wb24 ( pb , ts ) ; /* lower 24 bits of timestamp in ms */
avio_w8 ( pb , ( ts > > 24 ) & 0x7F ) ; /* MSB of ts in ms */
avio_wb24 ( pb , 0 ) ; /* StreamId = 0 */
avio_w8 ( pb , 23 ) ; /* ub[4] FrameType = 1, ub[4] CodecId = 7 */
avio_w8 ( pb , 2 ) ; /* AVC end of sequence */
avio_wb24 ( pb , 0 ) ; /* Always 0 for AVC EOS. */
avio_wb32 ( pb , 16 ) ; /* Size of FLV tag */
}
static void put_amf_double ( AVIOContext * pb , double d )
@ -172,7 +184,8 @@ static void put_amf_double(AVIOContext *pb, double d)
avio_wb64 ( pb , av_double2int ( d ) ) ;
}
static void put_amf_bool ( AVIOContext * pb , int b ) {
static void put_amf_bool ( AVIOContext * pb , int b )
{
avio_w8 ( pb , AMF_DATA_TYPE_BOOL ) ;
avio_w8 ( pb , ! ! b ) ;
}
@ -187,18 +200,19 @@ static int flv_write_header(AVFormatContext *s)
int64_t metadata_size_pos , data_size , metadata_count_pos ;
AVDictionaryEntry * tag = NULL ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
AVCodecContext * enc = s - > streams [ i ] - > codec ;
FLVStreamContext * sc ;
switch ( enc - > codec_type ) {
case AVMEDIA_TYPE_VIDEO :
if ( s - > streams [ i ] - > r_frame_rate . den & & s - > streams [ i ] - > r_frame_rate . num ) {
if ( s - > streams [ i ] - > r_frame_rate . den & &
s - > streams [ i ] - > r_frame_rate . num ) {
framerate = av_q2d ( s - > streams [ i ] - > r_frame_rate ) ;
} else {
framerate = 1 / av_q2d ( s - > streams [ i ] - > codec - > time_base ) ;
framerate = 1 / av_q2d ( s - > streams [ i ] - > codec - > time_base ) ;
}
video_enc = enc ;
if ( enc - > codec_tag = = 0 ) {
if ( enc - > codec_tag = = 0 ) {
av_log ( s , AV_LOG_ERROR , " video codec not compatible with flv \n " ) ;
return - 1 ;
}
@ -227,32 +241,32 @@ static int flv_write_header(AVFormatContext *s)
s - > streams [ i ] - > priv_data = sc ;
sc - > last_ts = - 1 ;
}
flv - > delay = AV_NOPTS_VALUE ;
avio_write ( pb , " FLV " , 3 ) ;
avio_w8 ( pb , 1 ) ;
avio_w8 ( pb , FLV_HEADER_FLAG_HASAUDIO * ! ! audio_enc
+ FLV_HEADER_FLAG_HASVIDEO * ! ! video_enc ) ;
avio_wb32 ( pb , 9 ) ;
avio_wb32 ( pb , 0 ) ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
if ( s - > streams [ i ] - > codec - > codec_tag = = 5 ) {
avio_w8 ( pb , 8 ) ; // message type
avio_wb24 ( pb , 0 ) ; // include flags
avio_wb24 ( pb , 0 ) ; // time stamp
avio_wb32 ( pb , 0 ) ; // reserved
avio_wb32 ( pb , 11 ) ; // size
flv - > reserved = 5 ;
avio_w8 ( pb , 1 ) ;
avio_w8 ( pb , FLV_HEADER_FLAG_HASAUDIO * ! ! audio_enc +
FLV_HEADER_FLAG_HASVIDEO * ! ! video_enc ) ;
avio_wb32 ( pb , 9 ) ;
avio_wb32 ( pb , 0 ) ;
for ( i = 0 ; i < s - > nb_streams ; i + + )
if ( s - > streams [ i ] - > codec - > codec_tag = = 5 ) {
avio_w8 ( pb , 8 ) ; // message type
avio_wb24 ( pb , 0 ) ; // include flags
avio_wb24 ( pb , 0 ) ; // time stamp
avio_wb32 ( pb , 0 ) ; // reserved
avio_wb32 ( pb , 11 ) ; // size
flv - > reserved = 5 ;
}
}
/* write meta_tag */
avio_w8 ( pb , 18 ) ; // tag type META
metadata_size_pos = avio_tell ( pb ) ;
avio_wb24 ( pb , 0 ) ; // size of data part (sum of all parts below)
avio_wb24 ( pb , 0 ) ; // time stamp
avio_wb32 ( pb , 0 ) ; // reserved
avio_w8 ( pb , 18 ) ; // tag type META
metadata_size_pos = avio_tell ( pb ) ;
avio_wb24 ( pb , 0 ) ; // size of data part (sum of all parts below)
avio_wb24 ( pb , 0 ) ; // timestamp
avio_wb32 ( pb , 0 ) ; // reserved
/* now data of data_size size */
@ -265,16 +279,18 @@ static int flv_write_header(AVFormatContext *s)
metadata_count_pos = avio_tell ( pb ) ;
metadata_count = 5 * ! ! video_enc +
5 * ! ! audio_enc +
1 * ! ! data_enc +
1 * ! ! data_enc +
2 ; // +2 for duration and file size
avio_wb32 ( pb , metadata_count ) ;
put_amf_string ( pb , " duration " ) ;
flv - > duration_offset = avio_tell ( pb ) ;
put_amf_double ( pb , s - > duration / AV_TIME_BASE ) ; // fill in the guessed duration, it'll be corrected later if incorrect
if ( video_enc ) {
// fill in the guessed duration, it'll be corrected later if incorrect
put_amf_double ( pb , s - > duration / AV_TIME_BASE ) ;
if ( video_enc ) {
put_amf_string ( pb , " width " ) ;
put_amf_double ( pb , video_enc - > width ) ;
@ -291,7 +307,7 @@ static int flv_write_header(AVFormatContext *s)
put_amf_double ( pb , video_enc - > codec_tag ) ;
}
if ( audio_enc ) {
if ( audio_enc ) {
put_amf_string ( pb , " audiodatarate " ) ;
put_amf_double ( pb , audio_enc - > bit_rate / 1024.0 ) ;
@ -337,14 +353,14 @@ static int flv_write_header(AVFormatContext *s)
}
put_amf_string ( pb , " filesize " ) ;
flv - > filesize_offset = avio_tell ( pb ) ;
flv - > filesize_offset = avio_tell ( pb ) ;
put_amf_double ( pb , 0 ) ; // delayed write
put_amf_string ( pb , " " ) ;
avio_w8 ( pb , AMF_END_OF_OBJECT ) ;
/* write total size of tag */
data_size = avio_tell ( pb ) - metadata_size_pos - 10 ;
data_size = avio_tell ( pb ) - metadata_size_pos - 10 ;
avio_seek ( pb , metadata_count_pos , SEEK_SET ) ;
avio_wb32 ( pb , metadata_count ) ;
@ -359,10 +375,10 @@ static int flv_write_header(AVFormatContext *s)
if ( enc - > codec_id = = CODEC_ID_AAC | | enc - > codec_id = = CODEC_ID_H264 | | enc - > codec_id = = CODEC_ID_MPEG4 ) {
int64_t pos ;
avio_w8 ( pb , enc - > codec_type = = AVMEDIA_TYPE_VIDEO ?
FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO ) ;
FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO ) ;
avio_wb24 ( pb , 0 ) ; // size patched later
avio_wb24 ( pb , 0 ) ; // ts
avio_w8 ( pb , 0 ) ; // ts ext
avio_w8 ( pb , 0 ) ; // ts ext
avio_wb24 ( pb , 0 ) ; // streamid
pos = avio_tell ( pb ) ;
if ( enc - > codec_id = = CODEC_ID_AAC ) {
@ -399,9 +415,8 @@ static int flv_write_trailer(AVFormatContext *s)
AVCodecContext * enc = s - > streams [ i ] - > codec ;
FLVStreamContext * sc = s - > streams [ i ] - > priv_data ;
if ( enc - > codec_type = = AVMEDIA_TYPE_VIDEO & &
( enc - > codec_id = = CODEC_ID_H264 | | enc - > codec_id = = CODEC_ID_MPEG4 ) ) {
( enc - > codec_id = = CODEC_ID_H264 | | enc - > codec_id = = CODEC_ID_MPEG4 ) )
put_avc_eos_tag ( pb , sc - > last_ts ) ;
}
}
file_size = avio_tell ( pb ) ;
@ -418,32 +433,35 @@ static int flv_write_trailer(AVFormatContext *s)
static int flv_write_packet ( AVFormatContext * s , AVPacket * pkt )
{
AVIOContext * pb = s - > pb ;
AVCodecContext * enc = s - > streams [ pkt - > stream_index ] - > codec ;
FLVContext * flv = s - > priv_data ;
AVIOContext * pb = s - > pb ;
AVCodecContext * enc = s - > streams [ pkt - > stream_index ] - > codec ;
FLVContext * flv = s - > priv_data ;
FLVStreamContext * sc = s - > streams [ pkt - > stream_index ] - > priv_data ;
unsigned ts ;
int size = pkt - > size ;
uint8_t * data = NULL ;
int size = pkt - > size ;
uint8_t * data = NULL ;
int flags , flags_size ;
// av_log(s, AV_LOG_DEBUG, "type:%d pts: %"PRId64" size:%d\n", enc->codec_type, timestamp, size);
// av_log(s, AV_LOG_DEBUG, "type:%d pts: %"PRId64" size:%d\n",
// enc->codec_type, timestamp, size);
if ( enc - > codec_id = = CODEC_ID_VP6 | | enc - > codec_id = = CODEC_ID_VP6F | |
enc - > codec_id = = CODEC_ID_VP6A | | enc - > codec_id = = CODEC_ID_AAC )
flags_size = 2 ;
else if ( enc - > codec_id = = CODEC_ID_H264 | | enc - > codec_id = = CODEC_ID_MPEG4 )
flags_size = 5 ;
if ( enc - > codec_id = = CODEC_ID_VP6 | | enc - > codec_id = = CODEC_ID_VP6F | |
enc - > codec_id = = CODEC_ID_VP6A | | enc - > codec_id = = CODEC_ID_AAC )
flags_size = 2 ;
else if ( enc - > codec_id = = CODEC_ID_H264 | | enc - > codec_id = = CODEC_ID_MPEG4 )
flags_size = 5 ;
else
flags_size = 1 ;
flags_size = 1 ;
switch ( enc - > codec_type ) {
case AVMEDIA_TYPE_VIDEO :
avio_w8 ( pb , FLV_TAG_TYPE_VIDEO ) ;
flags = enc - > codec_tag ;
if ( flags = = 0 ) {
av_log ( s , AV_LOG_ERROR , " video codec %s not compatible with flv \n " , avcodec_get_name ( enc - > codec_id ) ) ;
if ( flags = = 0 ) {
av_log ( s , AV_LOG_ERROR ,
" video codec %s not compatible with flv \n " ,
avcodec_get_name ( enc - > codec_id ) ) ;
return - 1 ;
}
@ -462,41 +480,42 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
default :
return AVERROR ( EINVAL ) ;
}
if ( enc - > codec_id = = CODEC_ID_H264 | | enc - > codec_id = = CODEC_ID_MPEG4 ) {
/* check if extradata looks like mp4 formated */
if ( enc - > extradata_size > 0 & & * ( uint8_t * ) enc - > extradata ! = 1 ) {
if ( enc - > extradata_size > 0 & & * ( uint8_t * ) enc - > extradata ! = 1 )
if ( ff_avc_parse_nal_units_buf ( pkt - > data , & data , & size ) < 0 )
return - 1 ;
}
} else if ( enc - > codec_id = = CODEC_ID_AAC & & pkt - > size > 2 & &
( AV_RB16 ( pkt - > data ) & 0xfff0 ) = = 0xfff0 ) {
av_log ( s , AV_LOG_ERROR , " malformated aac bitstream, use -absf aac_adtstoasc \n " ) ;
return - 1 ;
}
if ( flv - > delay = = AV_NOPTS_VALUE )
flv - > delay = - pkt - > dts ;
if ( pkt - > dts < - flv - > delay ) {
av_log ( s , AV_LOG_WARNING , " Packets are not in the proper order with "
" respect to DTS \n " ) ;
av_log ( s , AV_LOG_WARNING ,
" Packets are not in the proper order with respect to DTS\n " ) ;
return AVERROR ( EINVAL ) ;
}
ts = pkt - > dts + flv - > delay ; // add delay to force positive dts
/* check Speex packet duration */
if ( enc - > codec_id = = CODEC_ID_SPEEX & & ts - sc - > last_ts > 160 ) {
if ( enc - > codec_id = = CODEC_ID_SPEEX & & ts - sc - > last_ts > 160 )
av_log ( s , AV_LOG_WARNING , " Warning: Speex stream has more than "
" 8 frames per packet. Adobe Flash "
" Player cannot handle this! \n " ) ;
}
if ( sc - > last_ts < ts )
sc - > last_ts = ts ;
avio_wb24 ( pb , size + flags_size ) ;
avio_wb24 ( pb , ts ) ;
avio_w8 ( pb , ( ts > > 24 ) & 0x7F ) ; // timestamps are 32bits _signed_
avio_wb24 ( pb , flv - > reserved ) ;
avio_wb24 ( pb , size + flags_size ) ;
avio_wb24 ( pb , ts ) ;
avio_w8 ( pb , ( ts > > 24 ) & 0x7F ) ; // timestamps are 32 bits _signed_
avio_wb24 ( pb , flv - > reserved ) ;
if ( enc - > codec_type = = AVMEDIA_TYPE_DATA ) {
int data_size ;
@ -520,25 +539,26 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_seek ( pb , data_size + 10 - 3 , SEEK_CUR ) ;
avio_wb32 ( pb , data_size + 11 ) ;
} else {
avio_w8 ( pb , flags ) ;
if ( enc - > codec_id = = CODEC_ID_VP6 )
avio_w8 ( pb , 0 ) ;
if ( enc - > codec_id = = CODEC_ID_VP6F | | enc - > codec_id = = CODEC_ID_VP6A )
avio_w8 ( pb , enc - > extradata_size ? enc - > extradata [ 0 ] : 0 ) ;
else if ( enc - > codec_id = = CODEC_ID_AAC )
avio_w8 ( pb , 1 ) ; // AAC raw
else if ( enc - > codec_id = = CODEC_ID_H264 | | enc - > codec_id = = CODEC_ID_MPEG4 ) {
avio_w8 ( pb , 1 ) ; // AVC NALU
avio_wb24 ( pb , pkt - > pts - pkt - > dts ) ;
}
avio_w8 ( pb , flags ) ;
if ( enc - > codec_id = = CODEC_ID_VP6 )
avio_w8 ( pb , 0 ) ;
if ( enc - > codec_id = = CODEC_ID_VP6F | | enc - > codec_id = = CODEC_ID_VP6A )
avio_w8 ( pb , enc - > extradata_size ? enc - > extradata [ 0 ] : 0 ) ;
else if ( enc - > codec_id = = CODEC_ID_AAC )
avio_w8 ( pb , 1 ) ; // AAC raw
else if ( enc - > codec_id = = CODEC_ID_H264 | | enc - > codec_id = = CODEC_ID_MPEG4 ) {
avio_w8 ( pb , 1 ) ; // AVC NALU
avio_wb24 ( pb , pkt - > pts - pkt - > dts ) ;
}
avio_write ( pb , data ? data : pkt - > data , size ) ;
avio_write ( pb , data ? data : pkt - > data , size ) ;
avio_wb32 ( pb , size + flags_size + 11 ) ; // previous tag size
flv - > duration = FFMAX ( flv - > duration , pkt - > pts + flv - > delay + pkt - > duration ) ;
avio_wb32 ( pb , size + flags_size + 11 ) ; // previous tag size
flv - > duration = FFMAX ( flv - > duration ,
pkt - > pts + flv - > delay + pkt - > duration ) ;
}
avio_flush ( pb ) ;
avio_flush ( pb ) ;
av_free ( data ) ;
return pb - > error ;
@ -559,9 +579,9 @@ AVOutputFormat ff_flv_muxer = {
. write_header = flv_write_header ,
. write_packet = flv_write_packet ,
. write_trailer = flv_write_trailer ,
. codec_tag = ( const AVCodecTag * const [ ] ) {
flv_video_codec_ids , flv_audio_codec_ids , 0
} ,
. codec_tag = ( const AVCodecTag * const [ ] ) {
flv_video_codec_ids , flv_audio_codec_ids , 0
} ,
. flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |
AVFMT_TS_NONSTRICT ,
} ;