|
|
|
@ -19,18 +19,29 @@ |
|
|
|
|
#include "avformat.h" |
|
|
|
|
|
|
|
|
|
#define MAX_PAYLOAD_SIZE 4096 |
|
|
|
|
#define PRELOAD 45000 //0.5sec
|
|
|
|
|
//#define DEBUG_SEEK
|
|
|
|
|
|
|
|
|
|
#undef NDEBUG |
|
|
|
|
#include <assert.h> |
|
|
|
|
|
|
|
|
|
typedef struct PacketDesc { |
|
|
|
|
int64_t pts; |
|
|
|
|
int64_t dts; |
|
|
|
|
int size; |
|
|
|
|
int unwritten_size; |
|
|
|
|
int flags; |
|
|
|
|
struct PacketDesc *next; |
|
|
|
|
} PacketDesc; |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
uint8_t buffer[MAX_PAYLOAD_SIZE]; |
|
|
|
|
int buffer_ptr; |
|
|
|
|
int nb_frames; /* number of starting frame encountered (AC3) */ |
|
|
|
|
int frame_start_offset; /* starting offset of the frame + 1 (0 if none) */ |
|
|
|
|
FifoBuffer fifo; |
|
|
|
|
uint8_t id; |
|
|
|
|
int max_buffer_size; /* in bytes */ |
|
|
|
|
int buffer_index; |
|
|
|
|
PacketDesc *predecode_packet; |
|
|
|
|
PacketDesc *premux_packet; |
|
|
|
|
PacketDesc **next_packet; |
|
|
|
|
int packet_number; |
|
|
|
|
int64_t start_pts; |
|
|
|
|
int64_t start_dts; |
|
|
|
@ -51,8 +62,6 @@ typedef struct { |
|
|
|
|
int is_mpeg2; |
|
|
|
|
int is_vcd; |
|
|
|
|
int is_svcd; |
|
|
|
|
int scr_stream_index; /* stream from which the system clock is
|
|
|
|
|
computed (VBR case) */ |
|
|
|
|
int64_t last_scr; /* current system clock */ |
|
|
|
|
|
|
|
|
|
double vcd_padding_bitrate; //FIXME floats
|
|
|
|
@ -127,7 +136,7 @@ static int put_pack_header(AVFormatContext *ctx, |
|
|
|
|
static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_stream_id) |
|
|
|
|
{ |
|
|
|
|
MpegMuxContext *s = ctx->priv_data; |
|
|
|
|
int size, rate_bound, i, private_stream_coded, id; |
|
|
|
|
int size, i, private_stream_coded, id; |
|
|
|
|
PutBitContext pb; |
|
|
|
|
|
|
|
|
|
init_put_bits(&pb, buf, 128); |
|
|
|
@ -136,8 +145,7 @@ static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_str |
|
|
|
|
put_bits(&pb, 16, 0); |
|
|
|
|
put_bits(&pb, 1, 1); |
|
|
|
|
|
|
|
|
|
rate_bound = s->mux_rate; /* maximum bit rate of the multiplexed stream */ |
|
|
|
|
put_bits(&pb, 22, rate_bound); |
|
|
|
|
put_bits(&pb, 22, s->mux_rate); /* maximum bit rate of the multiplexed stream */ |
|
|
|
|
put_bits(&pb, 1, 1); /* marker */ |
|
|
|
|
if (s->is_vcd && only_for_stream_id==VIDEO_ID) { |
|
|
|
|
/* This header applies only to the video stream (see VCD standard p. IV-7)*/ |
|
|
|
@ -262,7 +270,6 @@ static int mpeg_mux_init(AVFormatContext *ctx) |
|
|
|
|
dts_id = DTS_ID; |
|
|
|
|
mpv_id = VIDEO_ID; |
|
|
|
|
lpcm_id = LPCM_ID; |
|
|
|
|
s->scr_stream_index = -1; |
|
|
|
|
for(i=0;i<ctx->nb_streams;i++) { |
|
|
|
|
st = ctx->streams[i]; |
|
|
|
|
stream = av_mallocz(sizeof(StreamInfo)); |
|
|
|
@ -300,9 +307,6 @@ static int mpeg_mux_init(AVFormatContext *ctx) |
|
|
|
|
s->audio_bound++; |
|
|
|
|
break; |
|
|
|
|
case CODEC_TYPE_VIDEO: |
|
|
|
|
/* by default, video is used for the SCR computation */ |
|
|
|
|
if (s->scr_stream_index == -1) |
|
|
|
|
s->scr_stream_index = i; |
|
|
|
|
stream->id = mpv_id++; |
|
|
|
|
if (s->is_vcd) |
|
|
|
|
/* see VCD standard, p. IV-7*/ |
|
|
|
@ -316,24 +320,31 @@ static int mpeg_mux_init(AVFormatContext *ctx) |
|
|
|
|
default: |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
fifo_init(&stream->fifo, 2*stream->max_buffer_size + 100*MAX_PAYLOAD_SIZE); //FIXME think about the size maybe dynamically realloc
|
|
|
|
|
stream->next_packet= &stream->premux_packet; |
|
|
|
|
} |
|
|
|
|
/* if no SCR, use first stream (audio) */ |
|
|
|
|
if (s->scr_stream_index == -1) |
|
|
|
|
s->scr_stream_index = 0; |
|
|
|
|
|
|
|
|
|
bitrate = 0; |
|
|
|
|
audio_bitrate = 0; |
|
|
|
|
video_bitrate = 0; |
|
|
|
|
for(i=0;i<ctx->nb_streams;i++) { |
|
|
|
|
int codec_rate; |
|
|
|
|
st = ctx->streams[i]; |
|
|
|
|
stream = (StreamInfo*) st->priv_data; |
|
|
|
|
|
|
|
|
|
bitrate += st->codec.bit_rate; |
|
|
|
|
|
|
|
|
|
if(st->codec.rc_max_rate || stream->id==VIDEO_ID) |
|
|
|
|
codec_rate= st->codec.rc_max_rate; |
|
|
|
|
else |
|
|
|
|
codec_rate= st->codec.bit_rate; |
|
|
|
|
|
|
|
|
|
if(!codec_rate) |
|
|
|
|
codec_rate= (1<<21)*8*50/ctx->nb_streams; |
|
|
|
|
|
|
|
|
|
bitrate += codec_rate; |
|
|
|
|
|
|
|
|
|
if (stream->id==AUDIO_ID) |
|
|
|
|
audio_bitrate += st->codec.bit_rate; |
|
|
|
|
audio_bitrate += codec_rate; |
|
|
|
|
else if (stream->id==VIDEO_ID) |
|
|
|
|
video_bitrate += st->codec.bit_rate; |
|
|
|
|
video_bitrate += codec_rate; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (s->is_vcd) { |
|
|
|
@ -367,7 +378,8 @@ static int mpeg_mux_init(AVFormatContext *ctx) |
|
|
|
|
} else { |
|
|
|
|
/* we increase slightly the bitrate to take into account the
|
|
|
|
|
headers. XXX: compute it exactly */ |
|
|
|
|
bitrate += 2000; |
|
|
|
|
bitrate += bitrate*5/100; |
|
|
|
|
bitrate += 10000; |
|
|
|
|
s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -395,7 +407,6 @@ static int mpeg_mux_init(AVFormatContext *ctx) |
|
|
|
|
|
|
|
|
|
for(i=0;i<ctx->nb_streams;i++) { |
|
|
|
|
stream = ctx->streams[i]->priv_data; |
|
|
|
|
stream->buffer_ptr = 0; |
|
|
|
|
stream->packet_number = 0; |
|
|
|
|
stream->start_pts = AV_NOPTS_VALUE; |
|
|
|
|
stream->start_dts = AV_NOPTS_VALUE; |
|
|
|
@ -432,7 +443,7 @@ static int get_vcd_padding_size(AVFormatContext *ctx, int64_t pts) |
|
|
|
|
{ |
|
|
|
|
int64_t full_pad_bytes; |
|
|
|
|
|
|
|
|
|
full_pad_bytes = (int64_t)((s->vcd_padding_bitrate * (pts / 90000.0)) / 8.0); |
|
|
|
|
full_pad_bytes = (int64_t)((s->vcd_padding_bitrate * (pts / 90000.0)) / 8.0); //FIXME this is wrong
|
|
|
|
|
pad_bytes = (int) (full_pad_bytes - s->vcd_padding_bytes_written); |
|
|
|
|
|
|
|
|
|
if (pad_bytes<0) |
|
|
|
@ -547,10 +558,23 @@ static void put_padding_packet(AVFormatContext *ctx, ByteIOContext *pb,int packe |
|
|
|
|
put_byte(pb, 0xff); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int get_nb_frames(AVFormatContext *ctx, StreamInfo *stream, int len){ |
|
|
|
|
int nb_frames=0; |
|
|
|
|
PacketDesc *pkt_desc= stream->premux_packet; |
|
|
|
|
|
|
|
|
|
while(len>0){
|
|
|
|
|
if(pkt_desc->size == pkt_desc->unwritten_size) |
|
|
|
|
nb_frames++; |
|
|
|
|
len -= pkt_desc->unwritten_size; |
|
|
|
|
pkt_desc= pkt_desc->next; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nb_frames; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* flush the packet on stream stream_index */ |
|
|
|
|
static void flush_packet(AVFormatContext *ctx, int stream_index,
|
|
|
|
|
int64_t pts, int64_t dts, int64_t scr) |
|
|
|
|
static int flush_packet(AVFormatContext *ctx, int stream_index,
|
|
|
|
|
int64_t pts, int64_t dts, int64_t scr, int trailer_size) |
|
|
|
|
{ |
|
|
|
|
MpegMuxContext *s = ctx->priv_data; |
|
|
|
|
StreamInfo *stream = ctx->streams[stream_index]->priv_data; |
|
|
|
@ -562,6 +586,7 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
|
int pad_packet_bytes = 0; |
|
|
|
|
int pes_flags; |
|
|
|
|
int general_pack = 0; /*"general" pack without data specific to one stream?*/ |
|
|
|
|
int nb_frames; |
|
|
|
|
|
|
|
|
|
id = stream->id; |
|
|
|
|
|
|
|
|
@ -572,10 +597,11 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
|
|
|
|
|
|
buf_ptr = buffer; |
|
|
|
|
|
|
|
|
|
if (((s->packet_number % s->pack_header_freq) == 0)) { |
|
|
|
|
if ((s->packet_number % s->pack_header_freq) == 0 || s->last_scr != scr) { |
|
|
|
|
/* output pack and systems header if needed */ |
|
|
|
|
size = put_pack_header(ctx, buf_ptr, scr); |
|
|
|
|
buf_ptr += size; |
|
|
|
|
s->last_scr= scr; |
|
|
|
|
|
|
|
|
|
if (s->is_vcd) { |
|
|
|
|
/* there is exactly one system header for each stream in a VCD MPEG,
|
|
|
|
@ -652,7 +678,23 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
|
startcode = 0x100 + id; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
stuffing_size = payload_size - stream->buffer_ptr; |
|
|
|
|
stuffing_size = payload_size - fifo_size(&stream->fifo, stream->fifo.rptr); |
|
|
|
|
|
|
|
|
|
// first byte doesnt fit -> reset pts/dts + stuffing
|
|
|
|
|
if(payload_size <= trailer_size && pts != AV_NOPTS_VALUE){ |
|
|
|
|
int timestamp_len=0; |
|
|
|
|
if(dts != pts)
|
|
|
|
|
timestamp_len += 5; |
|
|
|
|
if(pts != AV_NOPTS_VALUE) |
|
|
|
|
timestamp_len += s->is_mpeg2 ? 5 : 4; |
|
|
|
|
pts=dts= AV_NOPTS_VALUE; |
|
|
|
|
header_len -= timestamp_len; |
|
|
|
|
payload_size += timestamp_len; |
|
|
|
|
stuffing_size += timestamp_len; |
|
|
|
|
if(payload_size > trailer_size) |
|
|
|
|
stuffing_size += payload_size - trailer_size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (stuffing_size < 0) |
|
|
|
|
stuffing_size = 0; |
|
|
|
|
if (stuffing_size > 16) { /*<=16 for MPEG-1, <=32 for MPEG-2*/ |
|
|
|
@ -661,6 +703,8 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
|
payload_size -= stuffing_size; |
|
|
|
|
stuffing_size = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nb_frames= get_nb_frames(ctx, stream, payload_size - stuffing_size); |
|
|
|
|
|
|
|
|
|
put_be32(&ctx->pb, startcode); |
|
|
|
|
|
|
|
|
@ -739,13 +783,17 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
|
put_byte(&ctx->pb, stream->lpcm_header[2]); |
|
|
|
|
} else { |
|
|
|
|
/* AC3 */ |
|
|
|
|
put_byte(&ctx->pb, stream->nb_frames); |
|
|
|
|
put_be16(&ctx->pb, stream->frame_start_offset); |
|
|
|
|
put_byte(&ctx->pb, nb_frames); |
|
|
|
|
put_be16(&ctx->pb, trailer_size+1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* output data */ |
|
|
|
|
put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size); |
|
|
|
|
if(put_fifo(&ctx->pb, &stream->fifo, payload_size - stuffing_size, &stream->fifo.rptr) < 0) |
|
|
|
|
return -1; |
|
|
|
|
}else{ |
|
|
|
|
payload_size= |
|
|
|
|
stuffing_size= 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (pad_packet_bytes > 0) |
|
|
|
@ -763,8 +811,8 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
|
or some data.*/ |
|
|
|
|
if (!general_pack) |
|
|
|
|
stream->packet_number++; |
|
|
|
|
stream->nb_frames = 0; |
|
|
|
|
stream->frame_start_offset = 0; |
|
|
|
|
|
|
|
|
|
return payload_size - stuffing_size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void put_vcd_padding_sector(AVFormatContext *ctx) |
|
|
|
@ -832,22 +880,11 @@ static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts) |
|
|
|
|
|
|
|
|
|
/* XXX: system clock should be computed precisely, especially for
|
|
|
|
|
CBR case. The current mode gives at least something coherent */ |
|
|
|
|
if (stream_index == s->scr_stream_index |
|
|
|
|
if (stream_index == 0 |
|
|
|
|
&& pts != AV_NOPTS_VALUE) |
|
|
|
|
scr = pts; |
|
|
|
|
else |
|
|
|
|
scr = s->last_scr; |
|
|
|
|
|
|
|
|
|
/* "Sanity hack": make sure that the SCR does not overtake the pts of
|
|
|
|
|
buffered data that is still waiting to be written.*/ |
|
|
|
|
for(i=0;i<ctx->nb_streams;i++) { |
|
|
|
|
stream = ctx->streams[i]->priv_data; |
|
|
|
|
|
|
|
|
|
if(scr > stream->start_pts && stream->start_pts!=AV_NOPTS_VALUE) { |
|
|
|
|
/* av_log(ctx, AV_LOG_DEBUG, "mpeg: restricting scr to stream pts (scr=%0.3f, stream index=%d, stream_pts=%0.3f).\n", scr/90000.0, i, stream->start_pts / 90000.0); */ |
|
|
|
|
scr = stream->start_pts; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s->last_scr=scr; |
|
|
|
@ -855,6 +892,135 @@ static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts) |
|
|
|
|
return scr; |
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int remove_decoded_packets(AVFormatContext *ctx, int64_t scr){ |
|
|
|
|
// MpegMuxContext *s = ctx->priv_data;
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
for(i=0; i<ctx->nb_streams; i++){ |
|
|
|
|
AVStream *st = ctx->streams[i]; |
|
|
|
|
StreamInfo *stream = st->priv_data; |
|
|
|
|
PacketDesc *pkt_desc= stream->predecode_packet; |
|
|
|
|
|
|
|
|
|
while(pkt_desc && scr > pkt_desc->dts){ //FIXME > vs >=
|
|
|
|
|
if(stream->buffer_index < pkt_desc->size ||
|
|
|
|
|
stream->predecode_packet == stream->premux_packet){ |
|
|
|
|
av_log(ctx, AV_LOG_ERROR, "buffer underflow\n"); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
stream->buffer_index -= pkt_desc->size; |
|
|
|
|
|
|
|
|
|
stream->predecode_packet= pkt_desc->next; |
|
|
|
|
av_freep(&pkt_desc); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int output_packet(AVFormatContext *ctx, int flush){ |
|
|
|
|
MpegMuxContext *s = ctx->priv_data; |
|
|
|
|
AVStream *st; |
|
|
|
|
StreamInfo *stream; |
|
|
|
|
int i, avail_space, es_size, trailer_size; |
|
|
|
|
int best_i= -1; |
|
|
|
|
int best_score= INT_MIN; |
|
|
|
|
int ignore_constraints=0; |
|
|
|
|
int64_t scr= s->last_scr; |
|
|
|
|
|
|
|
|
|
retry: |
|
|
|
|
for(i=0; i<ctx->nb_streams; i++){ |
|
|
|
|
AVStream *st = ctx->streams[i]; |
|
|
|
|
StreamInfo *stream = st->priv_data; |
|
|
|
|
const int avail_data= fifo_size(&stream->fifo, stream->fifo.rptr); |
|
|
|
|
const int space= stream->max_buffer_size - stream->buffer_index; |
|
|
|
|
int rel_space= 1024*space / stream->max_buffer_size; |
|
|
|
|
|
|
|
|
|
if(s->packet_size > avail_data && !flush) |
|
|
|
|
return 0; |
|
|
|
|
if(avail_data==0) |
|
|
|
|
continue; |
|
|
|
|
assert(avail_data>0); |
|
|
|
|
|
|
|
|
|
if(space < s->packet_size && !ignore_constraints) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
if(rel_space > best_score){ |
|
|
|
|
best_score= rel_space; |
|
|
|
|
best_i = i; |
|
|
|
|
avail_space= space; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(best_i < 0){ |
|
|
|
|
int64_t best_dts= INT64_MAX; |
|
|
|
|
|
|
|
|
|
for(i=0; i<ctx->nb_streams; i++){ |
|
|
|
|
AVStream *st = ctx->streams[i]; |
|
|
|
|
StreamInfo *stream = st->priv_data; |
|
|
|
|
PacketDesc *pkt_desc= stream->predecode_packet; |
|
|
|
|
if(pkt_desc && pkt_desc->dts < best_dts) |
|
|
|
|
best_dts= pkt_desc->dts; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
av_log(ctx, AV_LOG_DEBUG, "bumping scr, scr:%f, dts:%f\n",
|
|
|
|
|
scr/90000.0, best_dts/90000.0); |
|
|
|
|
#endif |
|
|
|
|
if(best_dts == INT64_MAX) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
if(scr >= best_dts+1 && !ignore_constraints){ |
|
|
|
|
av_log(ctx, AV_LOG_ERROR, "packet too large, ignoring buffer limits to mux it\n"); |
|
|
|
|
ignore_constraints= 1; |
|
|
|
|
} |
|
|
|
|
scr= FFMAX(best_dts+1, scr); |
|
|
|
|
if(remove_decoded_packets(ctx, scr) < 0) |
|
|
|
|
return -1; |
|
|
|
|
goto retry; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
assert(best_i >= 0); |
|
|
|
|
|
|
|
|
|
st = ctx->streams[best_i]; |
|
|
|
|
stream = st->priv_data; |
|
|
|
|
|
|
|
|
|
assert(fifo_size(&stream->fifo, stream->fifo.rptr) > 0); |
|
|
|
|
|
|
|
|
|
assert(avail_space >= s->packet_size || ignore_constraints); |
|
|
|
|
|
|
|
|
|
if(stream->premux_packet->unwritten_size == stream->premux_packet->size) |
|
|
|
|
trailer_size= 0; |
|
|
|
|
else |
|
|
|
|
trailer_size= stream->premux_packet->unwritten_size; |
|
|
|
|
|
|
|
|
|
es_size= flush_packet(ctx, best_i, stream->premux_packet->pts, stream->premux_packet->dts, scr, trailer_size); |
|
|
|
|
|
|
|
|
|
if (s->is_vcd) { |
|
|
|
|
/* Write one or more padding sectors, if necessary, to reach
|
|
|
|
|
the constant overall bitrate.*/ |
|
|
|
|
int vcd_pad_bytes; |
|
|
|
|
|
|
|
|
|
while((vcd_pad_bytes = get_vcd_padding_size(ctx,stream->start_pts) ) >= s->packet_size){ //FIXME pts cannot be correct here
|
|
|
|
|
put_vcd_padding_sector(ctx); |
|
|
|
|
s->last_scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
stream->buffer_index += es_size; |
|
|
|
|
s->last_scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet
|
|
|
|
|
|
|
|
|
|
while(stream->premux_packet && stream->premux_packet->unwritten_size <= es_size){ |
|
|
|
|
es_size -= stream->premux_packet->unwritten_size; |
|
|
|
|
stream->premux_packet= stream->premux_packet->next; |
|
|
|
|
} |
|
|
|
|
if(es_size) |
|
|
|
|
stream->premux_packet->unwritten_size -= es_size; |
|
|
|
|
|
|
|
|
|
if(remove_decoded_packets(ctx, s->last_scr) < 0) |
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) |
|
|
|
|
{ |
|
|
|
@ -866,6 +1032,7 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) |
|
|
|
|
StreamInfo *stream = st->priv_data; |
|
|
|
|
int64_t pts, dts, new_start_pts, new_start_dts; |
|
|
|
|
int len, avail_size; |
|
|
|
|
PacketDesc *pkt_desc; |
|
|
|
|
|
|
|
|
|
pts= pkt->pts; |
|
|
|
|
dts= pkt->dts; |
|
|
|
@ -891,17 +1058,36 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) |
|
|
|
|
So the real data starts at SCR 36000+3*1200. */ |
|
|
|
|
pts = (pts + 36000 + 3600) & ((1LL << 33) - 1); |
|
|
|
|
dts = (dts + 36000 + 3600) & ((1LL << 33) - 1); |
|
|
|
|
}else{ |
|
|
|
|
pts = (pts + PRELOAD) & ((1LL << 33) - 1); |
|
|
|
|
dts = (dts + PRELOAD) & ((1LL << 33) - 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
update_scr(ctx,stream_index,pts); |
|
|
|
|
*stream->next_packet= |
|
|
|
|
pkt_desc= av_mallocz(sizeof(PacketDesc)); |
|
|
|
|
pkt_desc->pts= pts; |
|
|
|
|
pkt_desc->dts= dts; |
|
|
|
|
pkt_desc->unwritten_size= |
|
|
|
|
pkt_desc->size= size; |
|
|
|
|
if(!stream->predecode_packet) |
|
|
|
|
stream->predecode_packet= pkt_desc; |
|
|
|
|
stream->next_packet= &pkt_desc->next; |
|
|
|
|
|
|
|
|
|
if(stream->fifo.end - stream->fifo.buffer - fifo_size(&stream->fifo, stream->fifo.rptr) < size){ |
|
|
|
|
av_log(ctx, AV_LOG_ERROR, "fifo overflow\n"); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
fifo_write(&stream->fifo, buf, size, &stream->fifo.wptr); |
|
|
|
|
|
|
|
|
|
printf("%d: pts=%0.3f dts=%0.3f scr=%0.3f\n",
|
|
|
|
|
stream_index,
|
|
|
|
|
pts / 90000.0,
|
|
|
|
|
dts / 90000.0,
|
|
|
|
|
s->last_scr / 90000.0); |
|
|
|
|
#endif |
|
|
|
|
for(;;){ |
|
|
|
|
int ret= output_packet(ctx, 0); |
|
|
|
|
if(ret<0)
|
|
|
|
|
return ret; |
|
|
|
|
else if(ret==0) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
|
|
|
|
|
/* we assume here that pts != AV_NOPTS_VALUE */ |
|
|
|
|
new_start_pts = stream->start_pts; |
|
|
|
@ -931,8 +1117,6 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) |
|
|
|
|
stream->start_pts = new_start_pts; |
|
|
|
|
stream->start_dts = new_start_dts; |
|
|
|
|
stream->nb_frames++; |
|
|
|
|
if (stream->frame_start_offset == 0) |
|
|
|
|
stream->frame_start_offset = stream->buffer_ptr + 1; |
|
|
|
|
while (size > 0) { |
|
|
|
|
avail_size = get_packet_payload_size(ctx, stream_index, |
|
|
|
|
stream->start_pts,
|
|
|
|
@ -968,27 +1152,22 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) |
|
|
|
|
stream->start_dts = AV_NOPTS_VALUE; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int mpeg_mux_end(AVFormatContext *ctx) |
|
|
|
|
{ |
|
|
|
|
MpegMuxContext *s = ctx->priv_data; |
|
|
|
|
// MpegMuxContext *s = ctx->priv_data;
|
|
|
|
|
StreamInfo *stream; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
/* flush each packet */ |
|
|
|
|
for(i=0;i<ctx->nb_streams;i++) { |
|
|
|
|
stream = ctx->streams[i]->priv_data; |
|
|
|
|
if (stream->buffer_ptr > 0) { |
|
|
|
|
update_scr(ctx,i,stream->start_pts); |
|
|
|
|
|
|
|
|
|
/* NOTE: we can always write the remaining data as it was
|
|
|
|
|
tested before in mpeg_mux_write_packet() */ |
|
|
|
|
flush_packet(ctx, i, stream->start_pts, stream->start_dts,
|
|
|
|
|
s->last_scr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for(;;){ |
|
|
|
|
int ret= output_packet(ctx, 1); |
|
|
|
|
if(ret<0)
|
|
|
|
|
return ret; |
|
|
|
|
else if(ret==0) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* End header according to MPEG1 systems standard. We do not write
|
|
|
|
@ -997,6 +1176,12 @@ static int mpeg_mux_end(AVFormatContext *ctx) |
|
|
|
|
//put_be32(&ctx->pb, ISO_11172_END_CODE);
|
|
|
|
|
//put_flush_packet(&ctx->pb);
|
|
|
|
|
|
|
|
|
|
for(i=0;i<ctx->nb_streams;i++) { |
|
|
|
|
stream = ctx->streams[i]->priv_data; |
|
|
|
|
|
|
|
|
|
assert(fifo_size(&stream->fifo, stream->fifo.rptr) == 0); |
|
|
|
|
fifo_free(&stream->fifo); |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
#endif //CONFIG_ENCODERS
|
|
|
|
|