diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2013-03-21 00:41:22 +0400 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2013-03-21 00:41:26 +0400 |
commit | 426ebdf923f9826e456bb734299fa2d2b6199524 (patch) | |
tree | f30fd4ac99579f87dec2bb4df06e30cbb0ee8859 /libavformat | |
parent | b853103fe0e59edc8970462abc6c181610ad9216 (diff) | |
parent | 2753d4ebf067593070ca4e9b3ea1dbe6ace23ba3 (diff) |
Merge remote-tracking branch 'cigaes/master'
* cigaes/master:
lavfi/vf_yadif: use standard options parsing.
lavfi/vf_unsharp: use standard options parsing.
lavfi/vf_transpose: use standard options parsing.
lavfi/vf_pad: use standard options parsing.
lavfi/vf_fps: use standard options parsing.
lavfi/vf_fade: use standard options parsing.
lavi/vf_drawbox: use standard options parsing.
lavfi/vf_delogo: use standard options parsing.
lavfi/vf_decimate: use standard options parsing.
lavfi/vf_crop: use standard options parsing.
lavfi/af_volume: use standard options parsing.
lavfi/vf_tile: use standard options parsing.
lavfi/avf_concat: use standard options parsing.
lavfi: add common code to handle options parsing.
lavf/vobsub: free index pseudo-packet.
ffmpeg: fix freeing of sub2video frame.
lavfi: add sine audio source.
lavu/opt: add AV_OPT_TYPE_DURATION.
lavfi/concat: fix silence duration computation.
lavf/concatdec: support seeking.
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/concatdec.c | 98 | ||||
-rw-r--r-- | libavformat/mpeg.c | 11 |
2 files changed, 105 insertions, 4 deletions
diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c index 380ad4383f..5359ad149d 100644 --- a/libavformat/concatdec.c +++ b/libavformat/concatdec.c @@ -37,6 +37,7 @@ typedef struct { unsigned nb_files; AVFormatContext *avf; int safe; + int seekable; } ConcatContext; static int concat_probe(AVProbeData *probe) @@ -128,6 +129,8 @@ static int open_file(AVFormatContext *avf, unsigned fileno) ConcatFile *file = &cat->files[fileno]; int ret; + if (cat->avf) + avformat_close_input(&cat->avf); if ((ret = avformat_open_input(&cat->avf, file->url, NULL, NULL)) < 0 || (ret = avformat_find_stream_info(cat->avf, NULL)) < 0) { av_log(avf, AV_LOG_ERROR, "Impossible to open '%s'\n", file->url); @@ -223,8 +226,10 @@ static int concat_read_header(AVFormatContext *avf) break; time += cat->files[i].duration; } - if (i == cat->nb_files) + if (i == cat->nb_files) { avf->duration = time; + cat->seekable = 1; + } if ((ret = open_file(avf, 0)) < 0) FAIL(ret); @@ -257,7 +262,6 @@ static int open_next_file(AVFormatContext *avf) if (++fileno >= cat->nb_files) return AVERROR_EOF; - avformat_close_input(&cat->avf); return open_file(avf, fileno); } @@ -282,6 +286,95 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) return ret; } +static void rescale_interval(AVRational tb_in, AVRational tb_out, + int64_t *min_ts, int64_t *ts, int64_t *max_ts) +{ + *ts = av_rescale_q (* ts, tb_in, tb_out); + *min_ts = av_rescale_q_rnd(*min_ts, tb_in, tb_out, + AV_ROUND_UP | AV_ROUND_PASS_MINMAX); + *max_ts = av_rescale_q_rnd(*max_ts, tb_in, tb_out, + AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX); +} + +static int try_seek(AVFormatContext *avf, int stream, + int64_t min_ts, int64_t ts, int64_t max_ts, int flags) +{ + ConcatContext *cat = avf->priv_data; + int64_t t0 = cat->cur_file->start_time - cat->avf->start_time; + + ts -= t0; + min_ts = min_ts == INT64_MIN ? INT64_MIN : min_ts - t0; + max_ts = max_ts == INT64_MAX ? INT64_MAX : max_ts - t0; + if (stream >= 0) { + if (stream >= cat->avf->nb_streams) + return AVERROR(EIO); + rescale_interval(AV_TIME_BASE_Q, cat->avf->streams[stream]->time_base, + &min_ts, &ts, &max_ts); + } + return avformat_seek_file(cat->avf, stream, min_ts, ts, max_ts, flags); +} + +static int real_seek(AVFormatContext *avf, int stream, + int64_t min_ts, int64_t ts, int64_t max_ts, int flags) +{ + ConcatContext *cat = avf->priv_data; + int ret, left, right; + + if (stream >= 0) { + if (stream >= avf->nb_streams) + return AVERROR(EINVAL); + rescale_interval(avf->streams[stream]->time_base, AV_TIME_BASE_Q, + &min_ts, &ts, &max_ts); + } + + left = 0; + right = cat->nb_files; + while (right - left > 1) { + int mid = (left + right) / 2; + if (ts < cat->files[mid].start_time) + right = mid; + else + left = mid; + } + + if ((ret = open_file(avf, left)) < 0) + return ret; + + ret = try_seek(avf, stream, min_ts, ts, max_ts, flags); + if (ret < 0 && !(flags & AVSEEK_FLAG_BACKWARD) && + left < cat->nb_files - 1 && + cat->files[left + 1].start_time < max_ts) { + if ((ret = open_file(avf, left + 1)) < 0) + return ret; + ret = try_seek(avf, stream, min_ts, ts, max_ts, flags); + } + return ret; +} + +static int concat_seek(AVFormatContext *avf, int stream, + int64_t min_ts, int64_t ts, int64_t max_ts, int flags) +{ + ConcatContext *cat = avf->priv_data; + ConcatFile *cur_file_saved = cat->cur_file; + AVFormatContext *cur_avf_saved = cat->avf; + int ret; + + if (!cat->seekable) + return AVERROR(ESPIPE); /* XXX: can we use it? */ + if (flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME)) + return AVERROR(ENOSYS); + cat->avf = NULL; + if ((ret = real_seek(avf, stream, min_ts, ts, max_ts, flags)) < 0) { + if (cat->avf) + avformat_close_input(&cat->avf); + cat->avf = cur_avf_saved; + cat->cur_file = cur_file_saved; + } else { + avformat_close_input(&cur_avf_saved); + } + return ret; +} + #define OFFSET(x) offsetof(ConcatContext, x) #define DEC AV_OPT_FLAG_DECODING_PARAM @@ -307,5 +400,6 @@ AVInputFormat ff_concat_demuxer = { .read_header = concat_read_header, .read_packet = concat_read_packet, .read_close = concat_read_close, + .read_seek2 = concat_seek, .priv_class = &concat_class, }; diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c index 5387b092e4..f36f0db727 100644 --- a/libavformat/mpeg.c +++ b/libavformat/mpeg.c @@ -805,6 +805,8 @@ end: return ret; } +#define FAIL(r) do { ret = r; goto fail; } while (0) + static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) { MpegDemuxContext *vobsub = s->priv_data; @@ -838,7 +840,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) ret = mpegps_read_pes_header(vobsub->sub_ctx, NULL, &startcode, &pts, &dts); if (ret < 0) - return ret; + FAIL(ret); to_read = ret & 0xffff; /* this prevents reads above the current packet */ @@ -855,7 +857,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) ret = av_grow_packet(pkt, to_read); if (ret < 0) - return ret; + FAIL(ret); n = avio_read(pb, pkt->data + (pkt->size - to_read), to_read); if (n < to_read) @@ -870,7 +872,12 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->pos = idx_pkt.pos; pkt->stream_index = idx_pkt.stream_index; + av_free_packet(&idx_pkt); return 0; + +fail: + av_free_packet(&idx_pkt); + return ret; } static int vobsub_read_seek(AVFormatContext *s, int stream_index, |