@ -29,7 +29,6 @@
# include "avformat.h"
# include "internal.h"
# include "mpegts.h"
# include "adts.h"
# define PCR_TIME_BASE 27000000
@ -79,7 +78,11 @@ typedef struct MpegTSWrite {
int start_pid ;
int m2ts_mode ;
int reemit_pat_pmt ;
int reemit_pat_pmt ; // backward compatibility
# define MPEGTS_FLAG_REEMIT_PAT_PMT 0x01
# define MPEGTS_FLAG_AAC_LATM 0x02
int flags ;
} MpegTSWrite ;
/* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */
@ -103,6 +106,15 @@ static const AVOption options[] = {
{ " muxrate " , NULL , offsetof ( MpegTSWrite , mux_rate ) , AV_OPT_TYPE_INT , { 1 } , 0 , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM } ,
{ " pes_payload_size " , " Minimum PES packet payload in bytes " ,
offsetof ( MpegTSWrite , pes_payload_size ) , AV_OPT_TYPE_INT , { DEFAULT_PES_PAYLOAD_SIZE } , 0 , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM } ,
{ " mpegts_flags " , " MPEG-TS muxing flags " , offsetof ( MpegTSWrite , flags ) , AV_OPT_TYPE_FLAGS , { . dbl = 0 } , 0 , INT_MAX ,
AV_OPT_FLAG_ENCODING_PARAM , " mpegts_flags " } ,
{ " resend_headers " , " Reemit PAT/PMT before writing the next packet " ,
0 , AV_OPT_TYPE_CONST , { . dbl = MPEGTS_FLAG_REEMIT_PAT_PMT } , 0 , INT_MAX ,
AV_OPT_FLAG_ENCODING_PARAM , " mpegts_flags " } ,
{ " latm " , " Use LATM packetization for AAC " ,
0 , AV_OPT_TYPE_CONST , { . dbl = MPEGTS_FLAG_AAC_LATM } , 0 , INT_MAX ,
AV_OPT_FLAG_ENCODING_PARAM , " mpegts_flags " } ,
// backward compatibility
{ " resend_headers " , " Reemit PAT/PMT before writing the next packet " ,
offsetof ( MpegTSWrite , reemit_pat_pmt ) , AV_OPT_TYPE_INT , { 0 } , 0 , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM } ,
{ NULL } ,
@ -220,7 +232,11 @@ typedef struct MpegTSWriteStream {
int64_t payload_dts ;
int payload_flags ;
uint8_t * payload ;
ADTSContext * adts ;
uint8_t * adata ;
int adata_pos ;
int adata_size ;
AVFormatContext * amux ;
} MpegTSWriteStream ;
static void mpegts_write_pat ( AVFormatContext * s )
@ -242,7 +258,7 @@ static void mpegts_write_pat(AVFormatContext *s)
static void mpegts_write_pmt ( AVFormatContext * s , MpegTSService * service )
{
// MpegTSWrite *ts = s->priv_data;
MpegTSWrite * ts = s - > priv_data ;
uint8_t data [ 1012 ] , * q , * desc_length_ptr , * program_info_length_ptr ;
int val , stream_type , i ;
@ -281,7 +297,7 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
stream_type = STREAM_TYPE_AUDIO_MPEG1 ;
break ;
case CODEC_ID_AAC :
stream_type = STREAM_TYPE_AUDIO_AAC ;
stream_type = ( ts - > flags & MPEGTS_FLAG_AAC_LATM ) ? STREAM_TYPE_AUDIO_AAC_LATM : STREAM_TYPE_AUDIO_AAC ;
break ;
case CODEC_ID_AAC_LATM :
stream_type = STREAM_TYPE_AUDIO_AAC_LATM ;
@ -487,6 +503,19 @@ static void section_write_packet(MpegTSSection *s, const uint8_t *packet)
avio_write ( ctx - > pb , packet , TS_PACKET_SIZE ) ;
}
/* Write callback for audio packetizer */
static int mpegts_audio_write ( void * opaque , uint8_t * buf , int size )
{
MpegTSWriteStream * ts_st = ( MpegTSWriteStream * ) opaque ;
if ( ts_st - > adata_pos + size > ts_st - > adata_size )
return AVERROR ( EIO ) ;
memcpy ( ts_st - > adata + ts_st - > adata_pos , buf , size ) ;
ts_st - > adata_pos + = size ;
return 0 ;
}
static int mpegts_write_header ( AVFormatContext * s )
{
MpegTSWrite * ts = s - > priv_data ;
@ -498,6 +527,7 @@ static int mpegts_write_header(AVFormatContext *s)
const char * service_name ;
const char * provider_name ;
int * pids ;
int ret ;
if ( s - > max_delay < 0 ) /* Not set by the caller */
s - > max_delay = 0 ;
@ -538,12 +568,16 @@ static int mpegts_write_header(AVFormatContext *s)
st = s - > streams [ i ] ;
avpriv_set_pts_info ( st , 33 , 1 , 90000 ) ;
ts_st = av_mallocz ( sizeof ( MpegTSWriteStream ) ) ;
if ( ! ts_st )
if ( ! ts_st ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
st - > priv_data = ts_st ;
ts_st - > payload = av_mallocz ( ts - > pes_payload_size ) ;
if ( ! ts_st - > payload )
if ( ! ts_st - > payload ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
ts_st - > service = service ;
/* MPEG pid values < 16 are reserved. Applications which set st->id in
* this range are assigned a calculated pid . */
@ -553,15 +587,18 @@ static int mpegts_write_header(AVFormatContext *s)
ts_st - > pid = st - > id ;
} else {
av_log ( s , AV_LOG_ERROR , " Invalid stream id %d, must be less than 8191 \n " , st - > id ) ;
ret = AVERROR ( EINVAL ) ;
goto fail ;
}
if ( ts_st - > pid = = service - > pmt . pid ) {
av_log ( s , AV_LOG_ERROR , " Duplicate stream id %d \n " , ts_st - > pid ) ;
ret = AVERROR ( EINVAL ) ;
goto fail ;
}
for ( j = 0 ; j < i ; j + + )
if ( pids [ j ] = = ts_st - > pid ) {
av_log ( s , AV_LOG_ERROR , " Duplicate stream id %d \n " , ts_st - > pid ) ;
ret = AVERROR ( EINVAL ) ;
goto fail ;
}
pids [ i ] = ts_st - > pid ;
@ -576,12 +613,39 @@ static int mpegts_write_header(AVFormatContext *s)
pcr_st = st ;
}
if ( st - > codec - > codec_id = = CODEC_ID_AAC & &
st - > codec - > extradata_size > 0 ) {
ts_st - > adts = av_mallocz ( sizeof ( * ts_st - > adts ) ) ;
if ( ! ts_st - > adts )
st - > codec - > extradata_size > 0 )
{
AVStream * ast ;
uint8_t * buffer ;
int buffer_size = 32768 ;
ts_st - > amux = avformat_alloc_context ( ) ;
if ( ! ts_st - > amux ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
buffer = av_malloc ( buffer_size ) ;
if ( ! buffer ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
ts_st - > amux - > pb = avio_alloc_context ( buffer , buffer_size , AVIO_FLAG_WRITE ,
ts_st , NULL , mpegts_audio_write , NULL ) ;
if ( ! ts_st - > amux - > pb ) {
av_free ( buffer ) ;
ret = AVERROR ( ENOMEM ) ;
goto fail ;
if ( ff_adts_decode_extradata ( s , ts_st - > adts , st - > codec - > extradata ,
st - > codec - > extradata_size ) < 0 )
}
ts_st - > amux - > oformat = av_guess_format ( ( ts - > flags & MPEGTS_FLAG_AAC_LATM ) ? " latm " : " adts " , NULL , NULL ) ;
if ( ! ts_st - > amux - > oformat ) {
ret = AVERROR ( EINVAL ) ;
goto fail ;
}
ast = avformat_new_stream ( ts_st - > amux , NULL ) ;
ret = avcodec_copy_context ( ast - > codec , st - > codec ) ;
if ( ret ! = 0 )
goto fail ;
ret = avformat_write_header ( ts_st - > amux , NULL ) ;
if ( ret < 0 )
goto fail ;
}
}
@ -658,11 +722,15 @@ static int mpegts_write_header(AVFormatContext *s)
ts_st = st - > priv_data ;
if ( ts_st ) {
av_freep ( & ts_st - > payload ) ;
av_freep ( & ts_st - > adts ) ;
if ( ts_st - > amux ) {
av_free ( ts_st - > amux - > pb - > buffer ) ;
av_free ( ts_st - > amux - > pb ) ;
avformat_free_context ( ts_st - > amux ) ;
}
}
av_freep ( & st - > priv_data ) ;
}
return AVERROR ( EINVAL ) ;
return ret ;
}
/* send SDT, PAT and PMT tables regulary */
@ -994,9 +1062,15 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
int64_t dts = AV_NOPTS_VALUE , pts = AV_NOPTS_VALUE ;
if ( ts - > reemit_pat_pmt ) {
av_log ( s , AV_LOG_WARNING , " resend_headers option is deprecated, use -mpegts_flags resend_headers \n " ) ;
ts - > reemit_pat_pmt = 0 ;
ts - > flags | = MPEGTS_FLAG_REEMIT_PAT_PMT ;
}
if ( ts - > flags & MPEGTS_FLAG_REEMIT_PAT_PMT ) {
ts - > pat_packet_count = ts - > pat_packet_period - 1 ;
ts - > sdt_packet_count = ts - > sdt_packet_period - 1 ;
ts - > reemit_pat_pmt = 0 ;
ts - > flags & = ~ MPEGTS_FLAG_REEMIT_PAT_PMT ;
}
if ( pkt - > pts ! = AV_NOPTS_VALUE )
@ -1017,7 +1091,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
if ( pkt - > size < 5 | | AV_RB32 ( pkt - > data ) ! = 0x0000001 ) {
av_log ( s , AV_LOG_ERROR , " H.264 bitstream malformed, "
" no startcode found, use the h264_mp4toannexb bitstream filter (-bsf h264_mp4toannexb) \n " ) ;
return AVERROR_INVALIDDATA ;
return AVERROR ( EINVAL ) ;
}
do {
@ -1038,35 +1112,41 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
size = pkt - > size + 6 ;
}
} else if ( st - > codec - > codec_id = = CODEC_ID_AAC ) {
if ( pkt - > size < 2 )
if ( pkt - > size < 2 ) {
av_log ( s , AV_LOG_ERROR , " AAC packet too short \n " ) ;
return AVERROR_INVALIDDATA ;
}
if ( ( AV_RB16 ( pkt - > data ) & 0xfff0 ) ! = 0xfff0 ) {
ADTSContext * adts = ts_st - > adts ;
int new_size , err ;
if ( ! adts ) {
int ret ;
AVPacket pkt2 ;
if ( ! ts_st - > amux ) {
av_log ( s , AV_LOG_ERROR , " AAC bitstream not in ADTS format "
" and extradata missing \n " ) ;
return AVERROR_INVALIDDATA ;
}
new_size = ADTS_HEADER_SIZE + adts - > pce_size + pkt - > size ;
if ( ( unsigned ) new_size > = INT_MAX )
return AVERROR_INVALIDDATA ;
data = av_malloc ( new_size ) ;
av_init_packet ( & pkt2 ) ;
pkt2 . data = pkt - > data ;
pkt2 . size = pkt - > size ;
ts_st - > adata_size = 1024 + pkt - > size ;
ts_st - > adata = data = av_malloc ( ts_st - > adata_size ) ;
ts_st - > adata_pos = 0 ;
if ( ! data )
return AVERROR ( ENOMEM ) ;
err = ff_adts_write_frame_header ( adts , data , pkt - > size ,
adts - > pce_size ) ;
if ( er r < 0 ) {
ret = av_write_frame ( ts_st - > amux , & pkt2 ) ;
if ( ret < 0 ) {
av_free ( data ) ;
return er r;
return ret ;
}
if ( adts - > pce_size ) {
memcpy ( data + ADTS_HEADER_SIZE , adts - > pce_data , adts - > pce_size ) ;
adts - > pce_size = 0 ;
avio_flush ( ts_st - > amux - > pb ) ;
if ( ts_st - > amux - > pb - > error < 0 ) {
av_free ( data ) ;
return ts_st - > amux - > pb - > error ;
}
memcpy ( data + ADTS_HEADER_SIZE + adts - > pce_size , pkt - > data , pkt - > size ) ;
buf = data ;
size = new_size ;
buf = ts_st - > adata ;
size = ts_st - > adata_pos ;
}
}
@ -1154,7 +1234,11 @@ static int mpegts_write_end(AVFormatContext *s)
AVStream * st = s - > streams [ i ] ;
MpegTSWriteStream * ts_st = st - > priv_data ;
av_freep ( & ts_st - > payload ) ;
av_freep ( & ts_st - > adts ) ;
if ( ts_st - > amux ) {
av_free ( ts_st - > amux - > pb - > buffer ) ;
av_free ( ts_st - > amux - > pb ) ;
avformat_free_context ( ts_st - > amux ) ;
}
}
for ( i = 0 ; i < ts - > nb_services ; i + + ) {