use native timebase for seeking
direction flag for seeking Originally committed as revision 3577 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
ac8b03c0a8
commit
3ba1438dec
2
ffmpeg.c
2
ffmpeg.c
@ -2777,7 +2777,7 @@ static void opt_input_file(const char *filename)
|
|||||||
|
|
||||||
/* if seeking requested, we execute it */
|
/* if seeking requested, we execute it */
|
||||||
if (start_time != 0) {
|
if (start_time != 0) {
|
||||||
ret = av_seek_frame(ic, -1, timestamp);
|
ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "%s: could not seek to position %0.3f\n",
|
fprintf(stderr, "%s: could not seek to position %0.3f\n",
|
||||||
filename, (double)timestamp / AV_TIME_BASE);
|
filename, (double)timestamp / AV_TIME_BASE);
|
||||||
|
12
ffplay.c
12
ffplay.c
@ -92,6 +92,7 @@ typedef struct VideoState {
|
|||||||
int paused;
|
int paused;
|
||||||
int last_paused;
|
int last_paused;
|
||||||
int seek_req;
|
int seek_req;
|
||||||
|
int seek_flags;
|
||||||
int64_t seek_pos;
|
int64_t seek_pos;
|
||||||
AVFormatContext *ic;
|
AVFormatContext *ic;
|
||||||
int dtg_active_format;
|
int dtg_active_format;
|
||||||
@ -589,10 +590,11 @@ static double get_master_clock(VideoState *is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* seek in the stream */
|
/* seek in the stream */
|
||||||
static void stream_seek(VideoState *is, int64_t pos)
|
static void stream_seek(VideoState *is, int64_t pos, int rel)
|
||||||
{
|
{
|
||||||
is->seek_pos = pos;
|
is->seek_pos = pos;
|
||||||
is->seek_req = 1;
|
is->seek_req = 1;
|
||||||
|
is->seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pause or resume the video */
|
/* pause or resume the video */
|
||||||
@ -1335,7 +1337,7 @@ static int decode_thread(void *arg)
|
|||||||
/* add the stream start time */
|
/* add the stream start time */
|
||||||
if (ic->start_time != AV_NOPTS_VALUE)
|
if (ic->start_time != AV_NOPTS_VALUE)
|
||||||
timestamp += ic->start_time;
|
timestamp += ic->start_time;
|
||||||
ret = av_seek_frame(ic, -1, timestamp);
|
ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "%s: could not seek to position %0.3f\n",
|
fprintf(stderr, "%s: could not seek to position %0.3f\n",
|
||||||
is->filename, (double)timestamp / AV_TIME_BASE);
|
is->filename, (double)timestamp / AV_TIME_BASE);
|
||||||
@ -1412,7 +1414,7 @@ static int decode_thread(void *arg)
|
|||||||
#endif
|
#endif
|
||||||
if (is->seek_req) {
|
if (is->seek_req) {
|
||||||
/* XXX: must lock decoder threads */
|
/* XXX: must lock decoder threads */
|
||||||
ret = av_seek_frame(is->ic, -1, is->seek_pos);
|
ret = av_seek_frame(is->ic, -1, is->seek_pos, is->seek_flags);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
|
fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
|
||||||
}else{
|
}else{
|
||||||
@ -1682,7 +1684,7 @@ void event_loop(void)
|
|||||||
if (cur_stream) {
|
if (cur_stream) {
|
||||||
pos = get_master_clock(cur_stream);
|
pos = get_master_clock(cur_stream);
|
||||||
pos += incr;
|
pos += incr;
|
||||||
stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE));
|
stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), incr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1704,7 +1706,7 @@ void event_loop(void)
|
|||||||
ss = (ns%60);
|
ss = (ns%60);
|
||||||
fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
|
fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
|
||||||
hh, mm, ss, thh, tmm, tss);
|
hh, mm, ss, thh, tmm, tss);
|
||||||
stream_seek(cur_stream, (int64_t)(cur_stream->ic->start_time+frac*cur_stream->ic->duration));
|
stream_seek(cur_stream, (int64_t)(cur_stream->ic->start_time+frac*cur_stream->ic->duration), 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_VIDEORESIZE:
|
case SDL_VIDEORESIZE:
|
||||||
|
@ -757,14 +757,14 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos,
|
|||||||
return pts;
|
return pts;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts)
|
static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags)
|
||||||
{
|
{
|
||||||
ASFContext *asf = s->priv_data;
|
ASFContext *asf = s->priv_data;
|
||||||
|
|
||||||
if (asf->packet_size <= 0)
|
if (asf->packet_size <= 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if(av_seek_frame_binary(s, stream_index, pts)<0)
|
if(av_seek_frame_binary(s, stream_index, pts, flags)<0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
asf_reset_header(s);
|
asf_reset_header(s);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LIBAVFORMAT_BUILD 4618
|
#define LIBAVFORMAT_BUILD 4619
|
||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_INT FFMPEG_VERSION_INT
|
#define LIBAVFORMAT_VERSION_INT FFMPEG_VERSION_INT
|
||||||
#define LIBAVFORMAT_VERSION FFMPEG_VERSION
|
#define LIBAVFORMAT_VERSION FFMPEG_VERSION
|
||||||
@ -165,10 +165,15 @@ typedef struct AVInputFormat {
|
|||||||
/* close the stream. The AVFormatContext and AVStreams are not
|
/* close the stream. The AVFormatContext and AVStreams are not
|
||||||
freed by this function */
|
freed by this function */
|
||||||
int (*read_close)(struct AVFormatContext *);
|
int (*read_close)(struct AVFormatContext *);
|
||||||
/* seek at or before a given timestamp (given in AV_TIME_BASE
|
/**
|
||||||
units) relative to the frames in stream component stream_index */
|
* seek to a given timestamp relative to the frames in
|
||||||
|
* stream component stream_index
|
||||||
|
* @param stream_index must not be -1
|
||||||
|
* @param flags selects which direction should be preferred if no exact
|
||||||
|
* match is available
|
||||||
|
*/
|
||||||
int (*read_seek)(struct AVFormatContext *,
|
int (*read_seek)(struct AVFormatContext *,
|
||||||
int stream_index, int64_t timestamp);
|
int stream_index, int64_t timestamp, int flags);
|
||||||
/**
|
/**
|
||||||
* gets the next timestamp in AV_TIME_BASE units.
|
* gets the next timestamp in AV_TIME_BASE units.
|
||||||
*/
|
*/
|
||||||
@ -553,7 +558,7 @@ AVFormatContext *av_alloc_format_context(void);
|
|||||||
int av_find_stream_info(AVFormatContext *ic);
|
int av_find_stream_info(AVFormatContext *ic);
|
||||||
int av_read_packet(AVFormatContext *s, AVPacket *pkt);
|
int av_read_packet(AVFormatContext *s, AVPacket *pkt);
|
||||||
int av_read_frame(AVFormatContext *s, AVPacket *pkt);
|
int av_read_frame(AVFormatContext *s, AVPacket *pkt);
|
||||||
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp);
|
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
|
||||||
int av_read_play(AVFormatContext *s);
|
int av_read_play(AVFormatContext *s);
|
||||||
int av_read_pause(AVFormatContext *s);
|
int av_read_pause(AVFormatContext *s);
|
||||||
void av_close_input_file(AVFormatContext *s);
|
void av_close_input_file(AVFormatContext *s);
|
||||||
@ -561,11 +566,14 @@ AVStream *av_new_stream(AVFormatContext *s, int id);
|
|||||||
void av_set_pts_info(AVStream *s, int pts_wrap_bits,
|
void av_set_pts_info(AVStream *s, int pts_wrap_bits,
|
||||||
int pts_num, int pts_den);
|
int pts_num, int pts_den);
|
||||||
|
|
||||||
|
#define AVSEEK_FLAG_BACKWARD 1 ///< seek backward
|
||||||
|
#define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes
|
||||||
|
|
||||||
int av_find_default_stream_index(AVFormatContext *s);
|
int av_find_default_stream_index(AVFormatContext *s);
|
||||||
int av_index_search_timestamp(AVStream *st, int timestamp);
|
int av_index_search_timestamp(AVStream *st, int timestamp, int flags);
|
||||||
int av_add_index_entry(AVStream *st,
|
int av_add_index_entry(AVStream *st,
|
||||||
int64_t pos, int64_t timestamp, int distance, int flags);
|
int64_t pos, int64_t timestamp, int distance, int flags);
|
||||||
int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts);
|
int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags);
|
||||||
|
|
||||||
/* media file output */
|
/* media file output */
|
||||||
int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap);
|
int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap);
|
||||||
|
@ -1331,12 +1331,12 @@ static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
|
|||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts){
|
static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
|
||||||
MpegTSContext *ts = s->priv_data;
|
MpegTSContext *ts = s->priv_data;
|
||||||
uint8_t buf[TS_PACKET_SIZE];
|
uint8_t buf[TS_PACKET_SIZE];
|
||||||
int64_t pos;
|
int64_t pos;
|
||||||
|
|
||||||
if(av_seek_frame_binary(s, stream_index, target_ts) < 0)
|
if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pos= url_ftell(&s->pb);
|
pos= url_ftell(&s->pb);
|
||||||
|
@ -1373,11 +1373,11 @@ av_log(s, AV_LOG_DEBUG, "syncing from %lld\n", nut->packet_start[2]+1);
|
|||||||
return AV_NOPTS_VALUE;
|
return AV_NOPTS_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts){
|
static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
|
||||||
// NUTContext *nut = s->priv_data;
|
// NUTContext *nut = s->priv_data;
|
||||||
int64_t pos;
|
int64_t pos;
|
||||||
|
|
||||||
if(av_seek_frame_binary(s, stream_index, target_ts) < 0)
|
if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pos= url_ftell(&s->pb);
|
pos= url_ftell(&s->pb);
|
||||||
|
@ -907,31 +907,22 @@ int av_add_index_entry(AVStream *st,
|
|||||||
sizeof(AVIndexEntry));
|
sizeof(AVIndexEntry));
|
||||||
st->index_entries= entries;
|
st->index_entries= entries;
|
||||||
|
|
||||||
if(st->nb_index_entries){
|
index= av_index_search_timestamp(st, timestamp, 0);
|
||||||
index= av_index_search_timestamp(st, timestamp);
|
|
||||||
ie= &entries[index];
|
|
||||||
|
|
||||||
if(ie->timestamp != timestamp){
|
if(index<0){
|
||||||
if(ie->timestamp < timestamp){
|
|
||||||
index++; //index points to next instead of previous entry, maybe nonexistant
|
|
||||||
ie= &st->index_entries[index];
|
|
||||||
}else
|
|
||||||
assert(index==0);
|
|
||||||
|
|
||||||
if(index != st->nb_index_entries){
|
|
||||||
assert(index < st->nb_index_entries);
|
|
||||||
memmove(entries + index + 1, entries + index, sizeof(AVIndexEntry)*(st->nb_index_entries - index));
|
|
||||||
}
|
|
||||||
st->nb_index_entries++;
|
|
||||||
}else{
|
|
||||||
if(ie->pos == pos && distance < ie->min_distance) //dont reduce the distance
|
|
||||||
distance= ie->min_distance;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
index= st->nb_index_entries++;
|
index= st->nb_index_entries++;
|
||||||
ie= &entries[index];
|
ie= &entries[index];
|
||||||
|
assert(index==0 || ie[-1].timestamp < timestamp);
|
||||||
|
}else{
|
||||||
|
ie= &entries[index];
|
||||||
|
if(ie->timestamp != timestamp){
|
||||||
|
assert(ie->timestamp > timestamp);
|
||||||
|
memmove(entries + index + 1, entries + index, sizeof(AVIndexEntry)*(st->nb_index_entries - index));
|
||||||
|
st->nb_index_entries++;
|
||||||
|
}else if(ie->pos == pos && distance < ie->min_distance) //dont reduce the distance
|
||||||
|
distance= ie->min_distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
ie->pos = pos;
|
ie->pos = pos;
|
||||||
ie->timestamp = timestamp;
|
ie->timestamp = timestamp;
|
||||||
ie->min_distance= distance;
|
ie->min_distance= distance;
|
||||||
@ -979,31 +970,36 @@ static int is_raw_stream(AVFormatContext *s)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return the largest index entry whose timestamp is <=
|
/**
|
||||||
wanted_timestamp */
|
* gets the index for a specific timestamp.
|
||||||
int av_index_search_timestamp(AVStream *st, int wanted_timestamp)
|
* @param backward if non zero then the returned index will correspond to
|
||||||
|
* the timestamp which is <= the requested one, if backward is 0
|
||||||
|
* then it will be >=
|
||||||
|
* @return < 0 if no such timestamp could be found
|
||||||
|
*/
|
||||||
|
int av_index_search_timestamp(AVStream *st, int wanted_timestamp, int backward)
|
||||||
{
|
{
|
||||||
AVIndexEntry *entries= st->index_entries;
|
AVIndexEntry *entries= st->index_entries;
|
||||||
int nb_entries= st->nb_index_entries;
|
int nb_entries= st->nb_index_entries;
|
||||||
int a, b, m;
|
int a, b, m;
|
||||||
int64_t timestamp;
|
int64_t timestamp;
|
||||||
|
|
||||||
if (nb_entries <= 0)
|
a = - 1;
|
||||||
return -1;
|
b = nb_entries;
|
||||||
|
|
||||||
a = 0;
|
|
||||||
b = nb_entries - 1;
|
|
||||||
|
|
||||||
while (a < b) {
|
while (b - a > 1) {
|
||||||
m = (a + b + 1) >> 1;
|
m = (a + b) >> 1;
|
||||||
timestamp = entries[m].timestamp;
|
timestamp = entries[m].timestamp;
|
||||||
if (timestamp > wanted_timestamp) {
|
if(timestamp >= wanted_timestamp)
|
||||||
b = m - 1;
|
b = m;
|
||||||
} else {
|
if(timestamp <= wanted_timestamp)
|
||||||
a = m;
|
a = m;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return a;
|
m= backward ? a : b;
|
||||||
|
|
||||||
|
if(m == nb_entries)
|
||||||
|
return -1;
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEBUG_SEEK
|
#define DEBUG_SEEK
|
||||||
@ -1014,7 +1010,7 @@ int av_index_search_timestamp(AVStream *st, int wanted_timestamp)
|
|||||||
* @param target_ts target timestamp in the time base of the given stream
|
* @param target_ts target timestamp in the time base of the given stream
|
||||||
* @param stream_index stream number
|
* @param stream_index stream number
|
||||||
*/
|
*/
|
||||||
int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts){
|
int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
|
||||||
AVInputFormat *avif= s->iformat;
|
AVInputFormat *avif= s->iformat;
|
||||||
int64_t pos_min, pos_max, pos, pos_limit;
|
int64_t pos_min, pos_max, pos, pos_limit;
|
||||||
int64_t ts_min, ts_max, ts;
|
int64_t ts_min, ts_max, ts;
|
||||||
@ -1037,7 +1033,8 @@ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts
|
|||||||
if(st->index_entries){
|
if(st->index_entries){
|
||||||
AVIndexEntry *e;
|
AVIndexEntry *e;
|
||||||
|
|
||||||
index= av_index_search_timestamp(st, target_ts);
|
index= av_index_search_timestamp(st, target_ts, 1);
|
||||||
|
index= FFMAX(index, 0);
|
||||||
e= &st->index_entries[index];
|
e= &st->index_entries[index];
|
||||||
|
|
||||||
if(e->timestamp <= target_ts || e->pos == e->min_distance){
|
if(e->timestamp <= target_ts || e->pos == e->min_distance){
|
||||||
@ -1105,9 +1102,8 @@ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts
|
|||||||
if(no_change==0){
|
if(no_change==0){
|
||||||
int64_t approximate_keyframe_distance= pos_max - pos_limit;
|
int64_t approximate_keyframe_distance= pos_max - pos_limit;
|
||||||
// interpolate position (better than dichotomy)
|
// interpolate position (better than dichotomy)
|
||||||
pos = (int64_t)((double)(pos_max - pos_min) *
|
pos = av_rescale(target_ts - ts_min, pos_max - pos_min, ts_max - ts_min)
|
||||||
(double)(target_ts - ts_min) /
|
+ pos_min - approximate_keyframe_distance;
|
||||||
(double)(ts_max - ts_min)) + pos_min - approximate_keyframe_distance;
|
|
||||||
}else if(no_change==1){
|
}else if(no_change==1){
|
||||||
// bisection, if interpolation failed to change min or max pos last time
|
// bisection, if interpolation failed to change min or max pos last time
|
||||||
pos = (pos_min + pos_limit)>>1;
|
pos = (pos_min + pos_limit)>>1;
|
||||||
@ -1130,20 +1126,19 @@ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts
|
|||||||
av_log(s, AV_LOG_DEBUG, "%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%Ld noc:%d\n", pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit, start_pos, no_change);
|
av_log(s, AV_LOG_DEBUG, "%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%Ld noc:%d\n", pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit, start_pos, no_change);
|
||||||
#endif
|
#endif
|
||||||
assert(ts != AV_NOPTS_VALUE);
|
assert(ts != AV_NOPTS_VALUE);
|
||||||
if (target_ts < ts) {
|
if (target_ts <= ts) {
|
||||||
pos_limit = start_pos - 1;
|
pos_limit = start_pos - 1;
|
||||||
pos_max = pos;
|
pos_max = pos;
|
||||||
ts_max = ts;
|
ts_max = ts;
|
||||||
} else {
|
}
|
||||||
|
if (target_ts >= ts) {
|
||||||
pos_min = pos;
|
pos_min = pos;
|
||||||
ts_min = ts;
|
ts_min = ts;
|
||||||
/* check if we are lucky */
|
|
||||||
if (target_ts == ts)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = pos_min;
|
pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
|
||||||
|
ts = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min : ts_max;
|
||||||
#ifdef DEBUG_SEEK
|
#ifdef DEBUG_SEEK
|
||||||
pos_min = pos;
|
pos_min = pos;
|
||||||
ts_min = avif->read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
ts_min = avif->read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
||||||
@ -1155,18 +1150,51 @@ av_log(s, AV_LOG_DEBUG, "%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%L
|
|||||||
/* do the seek */
|
/* do the seek */
|
||||||
url_fseek(&s->pb, pos, SEEK_SET);
|
url_fseek(&s->pb, pos, SEEK_SET);
|
||||||
|
|
||||||
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++) {
|
for(i = 0; i < s->nb_streams; i++) {
|
||||||
st = s->streams[i];
|
AVStream *st2 = s->streams[i];
|
||||||
|
|
||||||
st->cur_dts = av_rescale(ts, st->time_base.den, AV_TIME_BASE*(int64_t)st->time_base.num);
|
st->cur_dts = av_rescale(ts,
|
||||||
|
st2->time_base.den * (int64_t)st ->time_base.num,
|
||||||
|
st ->time_base.den * (int64_t)st2->time_base.num);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int av_seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, int flags){
|
||||||
|
AVInputFormat *avif= s->iformat;
|
||||||
|
int64_t pos_min, pos_max;
|
||||||
|
#if 0
|
||||||
|
AVStream *st;
|
||||||
|
|
||||||
|
if (stream_index < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
st= s->streams[stream_index];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pos_min = s->data_offset;
|
||||||
|
pos_max = url_filesize(url_fileno(&s->pb)) - 1;
|
||||||
|
|
||||||
|
if (pos < pos_min) pos= pos_min;
|
||||||
|
else if(pos > pos_max) pos= pos_max;
|
||||||
|
|
||||||
|
url_fseek(&s->pb, pos, SEEK_SET);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
for(i = 0; i < s->nb_streams; i++) {
|
||||||
|
st2 = s->streams[i];
|
||||||
|
|
||||||
|
st->cur_dts = av_rescale(ie->timestamp,
|
||||||
|
st2->time_base.den * (int64_t)st ->time_base.num,
|
||||||
|
st ->time_base.den * (int64_t)st2->time_base.num);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int av_seek_frame_generic(AVFormatContext *s,
|
static int av_seek_frame_generic(AVFormatContext *s,
|
||||||
int stream_index, int64_t timestamp)
|
int stream_index, int64_t timestamp, int flags)
|
||||||
{
|
{
|
||||||
int index, i;
|
int index, i;
|
||||||
AVStream *st;
|
AVStream *st;
|
||||||
@ -1182,7 +1210,7 @@ static int av_seek_frame_generic(AVFormatContext *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
st = s->streams[stream_index];
|
st = s->streams[stream_index];
|
||||||
index = av_index_search_timestamp(st, timestamp);
|
index = av_index_search_timestamp(st, timestamp, flags & AVSEEK_FLAG_BACKWARD);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -1190,44 +1218,50 @@ static int av_seek_frame_generic(AVFormatContext *s,
|
|||||||
ie = &st->index_entries[index];
|
ie = &st->index_entries[index];
|
||||||
av_read_frame_flush(s);
|
av_read_frame_flush(s);
|
||||||
url_fseek(&s->pb, ie->pos, SEEK_SET);
|
url_fseek(&s->pb, ie->pos, SEEK_SET);
|
||||||
|
|
||||||
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 = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE*(int64_t)st->time_base.num);
|
for(i = 0; i < s->nb_streams; i++) {
|
||||||
|
AVStream *st2 = s->streams[i];
|
||||||
|
|
||||||
|
st->cur_dts = av_rescale(ie->timestamp,
|
||||||
|
st2->time_base.den * (int64_t)st ->time_base.num,
|
||||||
|
st ->time_base.den * (int64_t)st2->time_base.num);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seek to the key frame just before the frame at timestamp
|
* Seek to the key frame at timestamp.
|
||||||
* 'timestamp' in 'stream_index'.
|
* 'timestamp' in 'stream_index'.
|
||||||
* @param stream_index If stream_index is (-1), a default
|
* @param stream_index If stream_index is (-1), a default
|
||||||
* stream is selected
|
* stream is selected
|
||||||
* @param timestamp timestamp in AV_TIME_BASE units
|
* @param timestamp timestamp in AVStream.time_base units
|
||||||
|
* @param flags flags which select direction and seeking mode
|
||||||
* @return >= 0 on success
|
* @return >= 0 on success
|
||||||
*/
|
*/
|
||||||
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp)
|
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
AVStream *st;
|
AVStream *st;
|
||||||
|
|
||||||
av_read_frame_flush(s);
|
av_read_frame_flush(s);
|
||||||
|
|
||||||
|
if(flags & AVSEEK_FLAG_BYTE)
|
||||||
|
return av_seek_frame_byte(s, stream_index, timestamp, flags);
|
||||||
|
|
||||||
if(stream_index < 0){
|
if(stream_index < 0){
|
||||||
stream_index= av_find_default_stream_index(s);
|
stream_index= av_find_default_stream_index(s);
|
||||||
if(stream_index < 0)
|
if(stream_index < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
st= s->streams[stream_index];
|
||||||
|
timestamp = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num);
|
||||||
}
|
}
|
||||||
st= s->streams[stream_index];
|
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 */
|
/* first, we try the format specific seek */
|
||||||
if (s->iformat->read_seek)
|
if (s->iformat->read_seek)
|
||||||
ret = s->iformat->read_seek(s, stream_index, timestamp);
|
ret = s->iformat->read_seek(s, stream_index, timestamp, flags);
|
||||||
else
|
else
|
||||||
ret = -1;
|
ret = -1;
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
@ -1235,9 +1269,9 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(s->iformat->read_timestamp)
|
if(s->iformat->read_timestamp)
|
||||||
return av_seek_frame_binary(s, stream_index, timestamp);
|
return av_seek_frame_binary(s, stream_index, timestamp, flags);
|
||||||
else
|
else
|
||||||
return av_seek_frame_generic(s, stream_index, timestamp);
|
return av_seek_frame_generic(s, stream_index, timestamp, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************/
|
/*******************************************************/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user