diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c index 873b8e5dad..5fcc7f6084 100644 --- a/libavformat/mpeg.c +++ b/libavformat/mpeg.c @@ -346,7 +346,7 @@ static int get_packet_payload_size(AVFormatContext *ctx, int stream_index, if (s->is_mpeg2) buf_index += 3; if (pts != AV_NOPTS_VALUE) { - if (dts != AV_NOPTS_VALUE) + if (dts != pts) buf_index += 5 + 5; else buf_index += 5; @@ -410,7 +410,7 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, header_len = 0; } if (pts != AV_NOPTS_VALUE) { - if (dts != AV_NOPTS_VALUE) + if (dts != pts) header_len += 5 + 5; else header_len += 5; @@ -444,7 +444,7 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, put_byte(&ctx->pb, 0x80); /* mpeg2 id */ if (pts != AV_NOPTS_VALUE) { - if (dts != AV_NOPTS_VALUE) { + if (dts != pts) { put_byte(&ctx->pb, 0xc0); /* flags */ put_byte(&ctx->pb, header_len - 3); put_timestamp(&ctx->pb, 0x03, pts); @@ -460,7 +460,7 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, } } else { if (pts != AV_NOPTS_VALUE) { - if (dts != AV_NOPTS_VALUE) { + if (dts != pts) { put_timestamp(&ctx->pb, 0x03, pts); put_timestamp(&ctx->pb, 0x01, dts); } else { @@ -497,28 +497,75 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, stream->frame_start_offset = 0; } +/* XXX: move that to upper layer */ +/* XXX: we assume that there are always 'max_b_frames' between + reference frames. A better solution would be to use the AVFrame pts + field */ +static void compute_pts_dts(AVStream *st, int64_t *ppts, int64_t *pdts, + int64_t timestamp) +{ + int frame_delay; + int64_t pts, dts; + + if (st->codec.codec_type == CODEC_TYPE_VIDEO && + st->codec.max_b_frames != 0) { + frame_delay = (st->codec.frame_rate_base * 90000LL) / + st->codec.frame_rate; + if (timestamp == 0) { + /* specific case for first frame : DTS just before */ + pts = timestamp; + dts = timestamp - frame_delay; + } else { + timestamp -= frame_delay; + if (st->codec.coded_frame->pict_type == FF_B_TYPE) { + /* B frames has identical pts/dts */ + pts = timestamp; + dts = timestamp; + } else { + /* a reference frame has a pts equal to the dts of the + _next_ one */ + dts = timestamp; + pts = timestamp + (st->codec.max_b_frames + 1) * frame_delay; + } + } +#if 1 + printf("pts=%0.3f dts=%0.3f pict_type=%c\n", + pts / 90000.0, dts / 90000.0, + av_get_pict_type_char(st->codec.coded_frame->pict_type)); +#endif + } else { + pts = timestamp; + dts = timestamp; + } + *ppts = pts & ((1LL << 33) - 1); + *pdts = dts & ((1LL << 33) - 1); +} + static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index, - const uint8_t *buf, int size, int64_t pts) + const uint8_t *buf, int size, + int64_t timestamp) { MpegMuxContext *s = ctx->priv_data; AVStream *st = ctx->streams[stream_index]; StreamInfo *stream = st->priv_data; - int64_t dts, new_start_pts, new_start_dts; + int64_t pts, dts, new_start_pts, new_start_dts; int len, avail_size; + compute_pts_dts(st, &pts, &dts, timestamp); + /* 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) s->last_scr = pts; #if 0 - printf("%d: pts=%0.3f scr=%0.3f\n", - stream_index, pts / 90000.0, s->last_scr / 90000.0); + 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 - /* XXX: currently no way to pass dts, will change soon */ - dts = AV_NOPTS_VALUE; - /* we assume here that pts != AV_NOPTS_VALUE */ new_start_pts = stream->start_pts; new_start_dts = stream->start_dts;