diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2004-05-23 16:26:12 +0000 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2004-05-23 16:26:12 +0000 |
commit | cdd5034f892c8c6494d24a6991aa62748ee332db (patch) | |
tree | ca436f5cc904e9ca648f46bd0eea651b9e345a20 | |
parent | 9debb40040c4c040220b189c220e3089d8220cd0 (diff) | |
download | ffmpeg-cdd5034f892c8c6494d24a6991aa62748ee332db.tar.gz |
store index for seeking in the native timebase of each stream
set correct timebase for nut
merge mpeg-ts seeking with existing seeking code
10l fix in mpegts (27mhz vs. 90khz)
Originally committed as revision 3152 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | libavformat/asf.c | 2 | ||||
-rw-r--r-- | libavformat/avformat.h | 2 | ||||
-rw-r--r-- | libavformat/avidec.c | 15 | ||||
-rw-r--r-- | libavformat/mpeg.c | 4 | ||||
-rw-r--r-- | libavformat/mpegts.c | 122 | ||||
-rw-r--r-- | libavformat/nut.c | 11 | ||||
-rw-r--r-- | libavformat/raw.c | 2 | ||||
-rw-r--r-- | libavformat/utils.c | 65 |
8 files changed, 71 insertions, 152 deletions
diff --git a/libavformat/asf.c b/libavformat/asf.c index 0fb6540310..5ab128e716 100644 --- a/libavformat/asf.c +++ b/libavformat/asf.c @@ -732,7 +732,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, return AV_NOPTS_VALUE; } - pts= pkt->pts; + pts= pkt->pts * 1000 / AV_TIME_BASE; av_free_packet(pkt); if(pkt->flags&PKT_FLAG_KEY){ diff --git a/libavformat/avformat.h b/libavformat/avformat.h index f4dd4e239c..f91a8d7aa8 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -5,7 +5,7 @@ extern "C" { #endif -#define LIBAVFORMAT_BUILD 4612 +#define LIBAVFORMAT_BUILD 4613 #define LIBAVFORMAT_VERSION_INT FFMPEG_VERSION_INT #define LIBAVFORMAT_VERSION FFMPEG_VERSION diff --git a/libavformat/avidec.c b/libavformat/avidec.c index 4f939b365b..27d3991b8c 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -137,7 +137,6 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) st = av_new_stream(s, i); if (!st) goto fail; - av_set_pts_info(st, 64, 1, AV_TIME_BASE); ast = av_mallocz(sizeof(AVIStream)); if (!ast) @@ -204,14 +203,13 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) } ast->rate = rate; ast->scale = scale; + av_set_pts_info(st, 64, scale, rate); st->codec.frame_rate = rate; st->codec.frame_rate_base = scale; get_le32(pb); /* start */ nb_frames = get_le32(pb); st->start_time = 0; - st->duration = (double)nb_frames * - st->codec.frame_rate_base * AV_TIME_BASE / - st->codec.frame_rate; + st->duration = nb_frames; url_fskip(pb, size - 9 * 4); break; case MKTAG('a', 'u', 'd', 's'): @@ -233,6 +231,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) get_le32(pb); /* initial frame */ ast->scale = get_le32(pb); /* scale */ ast->rate = get_le32(pb); + av_set_pts_info(st, 64, ast->scale, ast->rate); ast->start= get_le32(pb); /* start */ length = get_le32(pb); /* length, in samples or bytes */ get_le32(pb); /* buffer size */ @@ -240,8 +239,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) ast->sample_size = get_le32(pb); /* sample ssize */ //av_log(NULL, AV_LOG_DEBUG, "%d %d %d %d\n", ast->scale, ast->rate, ast->sample_size, ast->start); st->start_time = 0; - if (ast->rate != 0) - st->duration = (int64_t)length * AV_TIME_BASE / ast->rate; + st->duration = length; url_fskip(pb, size - 12 * 4); } break; @@ -421,10 +419,9 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) ast = st->priv_data; /* XXX: how to handle B frames in avi ? */ + pkt->pts = ast->frame_offset; if(ast->sample_size) - pkt->pts = ((int64_t)ast->frame_offset * ast->scale* AV_TIME_BASE) / (ast->rate * ast->sample_size); - else - pkt->pts = ((int64_t)ast->frame_offset * ast->scale* AV_TIME_BASE) / ast->rate; + pkt->pts /= ast->sample_size; //printf("%Ld %d %d %d %d\n", pkt->pts, ast->frame_offset, ast->scale, AV_TIME_BASE, ast->rate); pkt->stream_index = n; /* FIXME: We really should read index for that */ diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c index a5feba8758..6618d5f469 100644 --- a/libavformat/mpeg.c +++ b/libavformat/mpeg.c @@ -1312,7 +1312,7 @@ static int mpegps_read_pes_header(AVFormatContext *s, int i; for(i=0; i<s->nb_streams; i++){ if(startcode == s->streams[i]->id) { - av_add_index_entry(s->streams[i], *ppos, dts*AV_TIME_BASE/90000, 0, 0 /* FIXME keyframe? */); + av_add_index_entry(s->streams[i], *ppos, dts, 0, 0 /* FIXME keyframe? */); } } } @@ -1430,7 +1430,7 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index, printf("pos=0x%llx dts=0x%llx %0.3f\n", pos, dts, dts / 90000.0); #endif *ppos = pos; - return dts*AV_TIME_BASE/90000; + return dts; } #ifdef CONFIG_ENCODERS diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index a7c442753a..747b00f47f 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -768,7 +768,7 @@ static void mpegts_push_data(void *opaque, } st = av_new_stream(pes->stream, pes->pid); if (st) { - av_set_pts_info(st, 60, 1, 27000000); + av_set_pts_info(st, 60, 1, 90000); st->priv_data = pes; st->codec.codec_type = codec_type; st->codec.codec_id = codec_id; @@ -1284,14 +1284,14 @@ static int mpegts_read_close(AVFormatContext *s) } static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index, - int64_t *ppos, int find_next) + int64_t *ppos, int64_t pos_limit) { MpegTSContext *ts = s->priv_data; int64_t pos, timestamp; uint8_t buf[TS_PACKET_SIZE]; int pcr_l, pid; - - pos = *ppos; + const int find_next= 1; + pos = ((*ppos + ts->raw_packet_size - 1) / ts->raw_packet_size) * ts->raw_packet_size; if (find_next) { for(;;) { url_fseek(&s->pb, pos, SEEK_SET); @@ -1320,117 +1320,8 @@ static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index, } } *ppos = pos; - return timestamp; -} - -typedef int64_t ReadTimestampFunc(AVFormatContext *s, int stream_index, - int64_t *ppos, int find_next); - -static int64_t do_block_align(int64_t val, int block_align) -{ - return (val / block_align) * block_align; -} -/* XXX: use it in other formats */ -static int timestamp_read_seek(AVFormatContext *s, - int stream_index, int64_t timestamp, - ReadTimestampFunc *read_timestamp, - int block_align) -{ - int64_t pos_min, pos_max, pos; - int64_t dts_min, dts_max, dts; - -#ifdef DEBUG_SEEK - printf("read_seek: %d %0.3f\n", stream_index, timestamp / 90000.0); -#endif - - pos_min = 0; - dts_min = read_timestamp(s, stream_index, &pos_min, 1); - if (dts_min == AV_NOPTS_VALUE) { - /* we can reach this case only if no PTS are present in - the whole stream */ - return -1; - } - pos_max = do_block_align(url_filesize(url_fileno(&s->pb)), block_align) - - block_align; - dts_max = read_timestamp(s, stream_index, &pos_max, 0); - - while (pos_min <= pos_max) { -#ifdef DEBUG_SEEK - printf("pos_min=0x%llx pos_max=0x%llx dts_min=%0.3f dts_max=%0.3f\n", - pos_min, pos_max, - dts_min / 90000.0, dts_max / 90000.0); -#endif - if (timestamp <= dts_min) { - pos = pos_min; - goto found; - } else if (timestamp >= dts_max) { - pos = pos_max; - goto found; - } else { - /* interpolate position (better than dichotomy) */ - pos = (int64_t)((double)(pos_max - pos_min) * - (double)(timestamp - dts_min) / - (double)(dts_max - dts_min)) + pos_min; - pos = do_block_align(pos, block_align); - } -#ifdef DEBUG_SEEK - printf("pos=0x%llx\n", pos); -#endif - /* read the next timestamp */ - dts = read_timestamp(s, stream_index, &pos, 1); - /* check if we are lucky */ - if (dts == AV_NOPTS_VALUE) { - /* should never happen */ - pos = pos_min; - goto found; - } else if (timestamp == dts) { - goto found; - } else if (timestamp < dts) { - pos_max = pos; - dts_max = read_timestamp(s, stream_index, &pos_max, 0); - if (dts_max == AV_NOPTS_VALUE) { - /* should never happen */ - break; - } else if (timestamp >= dts_max) { - pos = pos_max; - goto found; - } - } else { - pos_min = pos + block_align; - dts_min = read_timestamp(s, stream_index, &pos_min, 1); - if (dts_min == AV_NOPTS_VALUE) { - /* should never happen */ - goto found; - } else if (timestamp <= dts_min) { - goto found; - } - } - } - pos = pos_min; - found: -#ifdef DEBUG_SEEK - pos_min = pos; - dts_min = read_timestamp(s, stream_index, &pos_min, 1); - pos_min += block_align; - dts_max = read_timestamp(s, stream_index, &pos_min, 1); - printf("pos=0x%llx %0.3f<=%0.3f<=%0.3f\n", - pos, dts_min / 90000.0, timestamp / 90000.0, dts_max / 90000.0); -#endif - /* do the seek */ - url_fseek(&s->pb, pos, SEEK_SET); - return 0; -} - -static int mpegts_read_seek(AVFormatContext *s, - int stream_index, int64_t timestamp) -{ - MpegTSContext *ts = s->priv_data; - - timestamp = (timestamp * 90000) / AV_TIME_BASE; - - return timestamp_read_seek(s, stream_index, timestamp, - mpegts_get_pcr, ts->raw_packet_size); + return timestamp; } /**************************************************************/ @@ -1494,7 +1385,8 @@ AVInputFormat mpegts_demux = { mpegts_read_header, mpegts_read_packet, mpegts_read_close, - mpegts_read_seek, + NULL, //mpegts_read_seek, + mpegts_get_pcr, .flags = AVFMT_SHOW_IDS, }; diff --git a/libavformat/nut.c b/libavformat/nut.c index d5b213a1c3..cb327675fb 100644 --- a/libavformat/nut.c +++ b/libavformat/nut.c @@ -570,7 +570,6 @@ static int nut_write_header(AVFormatContext *s) int nom, denom, gcd; codec = &s->streams[i]->codec; - av_set_pts_info(s->streams[i], 60, 1, AV_TIME_BASE); put_be64(bc, STREAM_STARTCODE); put_packetheader(nut, bc, 120 + codec->extradata_size, 1); @@ -607,6 +606,7 @@ static int nut_write_header(AVFormatContext *s) denom /= gcd; nut->stream[i].rate_num= nom; nut->stream[i].rate_den= denom; + av_set_pts_info(s->streams[i], 60, denom, nom); put_v(bc, codec->bit_rate); put_vb(bc, 0); /* no language code */ @@ -706,8 +706,6 @@ static int nut_write_packet(AVFormatContext *s, int stream_index, if (stream_index > s->nb_streams) return 1; - pts= av_rescale(pts, stream->rate_num, stream->rate_den*(int64_t)AV_TIME_BASE); - enc = &s->streams[stream_index]->codec; key_frame = enc->coded_frame->key_frame; if(enc->coded_frame->pts != AV_NOPTS_VALUE) @@ -944,7 +942,6 @@ static int decode_stream_header(NUTContext *nut){ st = av_new_stream(s, stream_id); if (!st) return AVERROR_NOMEM; - av_set_pts_info(st, 60, 1, AV_TIME_BASE); class = get_v(bc); tmp = get_vb(bc); @@ -1004,6 +1001,7 @@ static int decode_stream_header(NUTContext *nut){ av_log(s, AV_LOG_ERROR, "Stream header %d checksum missmatch\n", stream_id); return -1; } + av_set_pts_info(s->streams[stream_id], 60, denom, nom); nut->stream[stream_id].rate_num= nom; nut->stream[stream_id].rate_den= denom; return 0; @@ -1175,12 +1173,11 @@ static int decode_frame_header(NUTContext *nut, int *key_frame_ret, int64_t *pts } if(*key_frame_ret){ - int64_t av_pts= pts * AV_TIME_BASE * stream->rate_den / stream->rate_num; // av_log(s, AV_LOG_DEBUG, "stream:%d start:%lld pts:%lld length:%lld\n",stream_id, frame_start, av_pts, frame_start - nut->stream[stream_id].last_sync_pos); av_add_index_entry( s->streams[stream_id], frame_start, - av_pts, + pts, frame_start - nut->stream[stream_id].last_sync_pos, AVINDEX_KEYFRAME); nut->stream[stream_id].last_sync_pos= frame_start; @@ -1202,7 +1199,7 @@ av_log(s, AV_LOG_DEBUG, "fs:%lld fc:%d ft:%d kf:%d pts:%lld size:%d mul:%d lsb:% } *stream_id_ret = stream_id; - *pts_ret = pts * AV_TIME_BASE * stream->rate_den / stream->rate_num; + *pts_ret = pts; update(nut, stream_id, frame_start, frame_type, frame_code, *key_frame_ret, size, pts); diff --git a/libavformat/raw.c b/libavformat/raw.c index b650fd76ae..fa3a1336d2 100644 --- a/libavformat/raw.c +++ b/libavformat/raw.c @@ -159,7 +159,7 @@ int pcm_read_seek(AVFormatContext *s, return -1; /* compute the position by aligning it to block_align */ - pos = (timestamp * byte_rate) / AV_TIME_BASE; + pos = av_rescale(timestamp * byte_rate, st->time_base.num, st->time_base.den); pos = (pos / block_align) * block_align; /* recompute exact position */ diff --git a/libavformat/utils.c b/libavformat/utils.c index 98110ab4b4..76ad4d4a36 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -634,6 +634,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, } /* this is tricky: the dts must be incremented by the duration of the frame we are displaying, i.e. the last I or P frame */ + //FIXME / XXX this is wrong if duration is wrong if (st->last_IP_duration == 0) st->cur_dts += pkt->duration; else @@ -656,6 +657,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, st->cur_dts = pkt->pts; pkt->dts = pkt->pts; } + //FIXME / XXX this will drift away from the exact solution st->cur_dts += pkt->duration; } @@ -883,7 +885,10 @@ static void av_read_frame_flush(AVFormatContext *s) } } -/* add a index entry into a sorted list updateing if it is already there */ +/** + * add a index entry into a sorted list updateing if it is already there. + * @param timestamp timestamp in the timebase of the given stream + */ int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, int distance, int flags) { @@ -946,7 +951,8 @@ static void av_build_index_raw(AVFormatContext *s) break; if (pkt->stream_index == 0 && st->parser && (pkt->flags & PKT_FLAG_KEY)) { - av_add_index_entry(st, st->parser->frame_offset, pkt->dts, + int64_t dts= av_rescale(pkt->dts, st->time_base.den, AV_TIME_BASE*(int64_t)st->time_base.num); + av_add_index_entry(st, st->parser->frame_offset, dts, 0, AVINDEX_KEYFRAME); } av_free_packet(pkt); @@ -996,20 +1002,23 @@ int av_index_search_timestamp(AVStream *st, int wanted_timestamp) #define DEBUG_SEEK +/** + * Does a binary search using av_index_search_timestamp() and AVCodec.read_timestamp(). + * this isnt supposed to be called directly by a user application, but by demuxers + * @param target_ts target timestamp in the time base of the given stream + * @param stream_index stream number + */ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts){ AVInputFormat *avif= s->iformat; int64_t pos_min, pos_max, pos, pos_limit; int64_t ts_min, ts_max, ts; int64_t start_pos; - int index, no_change; + int index, no_change, i; AVStream *st; - if (stream_index < 0) { - stream_index = av_find_default_stream_index(s); - if (stream_index < 0) - return -1; - } - + if (stream_index < 0) + return -1; + #ifdef DEBUG_SEEK av_log(s, AV_LOG_DEBUG, "read_seek: %d %lld\n", stream_index, target_ts); #endif @@ -1139,7 +1148,13 @@ av_log(s, AV_LOG_DEBUG, "%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%L #endif /* do the seek */ url_fseek(&s->pb, pos, SEEK_SET); - st->cur_dts = ts_min; + + ts= av_rescale(ts_min, AV_TIME_BASE*(int64_t)st->time_base.num, st->time_base.den); + for(i = 0; i < s->nb_streams; i++) { + st = s->streams[i]; + + st->cur_dts = ts; + } return 0; } @@ -1147,7 +1162,7 @@ av_log(s, AV_LOG_DEBUG, "%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%L static int av_seek_frame_generic(AVFormatContext *s, int stream_index, int64_t timestamp) { - int index; + int index, i; AVStream *st; AVIndexEntry *ie; @@ -1160,8 +1175,6 @@ static int av_seek_frame_generic(AVFormatContext *s, s->index_built = 1; } - if (stream_index < 0) - stream_index = 0; st = s->streams[stream_index]; index = av_index_search_timestamp(st, timestamp); if (index < 0) @@ -1171,20 +1184,40 @@ static int av_seek_frame_generic(AVFormatContext *s, ie = &st->index_entries[index]; av_read_frame_flush(s); url_fseek(&s->pb, ie->pos, SEEK_SET); - st->cur_dts = ie->timestamp; + + timestamp= av_rescale(ie->timestamp, AV_TIME_BASE*(int64_t)st->time_base.num, st->time_base.den); + for(i = 0; i < s->nb_streams; i++) { + st = s->streams[i]; + + st->cur_dts = timestamp; + } + return 0; } /** * Seek to the key frame just before the frame at timestamp - * 'timestamp' in 'stream_index'. If stream_index is (-1), a default - * stream is selected + * 'timestamp' in 'stream_index'. + * @param stream_index If stream_index is (-1), a default + * stream is selected + * @param timestamp timestamp in AV_TIME_BASE units + * @return >= 0 on success */ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp) { int ret; + AVStream *st; av_read_frame_flush(s); + + if(stream_index < 0){ + stream_index= av_find_default_stream_index(s); + if(stream_index < 0) + return -1; + } + st= s->streams[stream_index]; + + timestamp = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num); /* first, we try the format specific seek */ if (s->iformat->read_seek) |