[FFmpeg-devel] [PATCH] ffprobe: add -ss option
Clément Bœsch
u at pkh.me
Tue Sep 17 14:22:17 CEST 2013
On Mon, Sep 16, 2013 at 06:44:52PM +0200, Stefano Sabatini wrote:
> On date Monday 2013-09-16 18:09:38 +0200, Stefano Sabatini encoded:
> > On date Sunday 2013-09-15 20:15:08 +0200, Stefano Sabatini encoded:
> [...]
> > Updated, #N duration specification not yet implemented (I'll probably
> > do in a further patch). The new syntax is more flexible but the result
> > seems a bit overkill (+189 lines of code).
>
> Updated with that change. I'll ruminate upon the syntax a few days and
> push if nobody wants to review or proposes some changes (also
> documentation review is welcome).
> --
> FFmpeg = Frenzy and Frenzy Muttering Practical Ecstatic God
> From fbee237bfbf257a923b573542c5edcff19f3b68b Mon Sep 17 00:00:00 2001
> From: Stefano Sabatini <stefasab at gmail.com>
> Date: Mon, 22 Oct 2012 16:01:29 +0200
> Subject: [PATCH] ffprobe: add read_intervals option
>
> This is also useful to test seeking on an input file.
>
> TODO: add Changelog entry
>
> This also address trac ticket #1437.
> ---
> doc/ffprobe.texi | 53 ++++++++++++++
> ffprobe.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 263 insertions(+), 2 deletions(-)
>
> diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi
> index 20f5f4a..f6980a9 100644
> --- a/doc/ffprobe.texi
> +++ b/doc/ffprobe.texi
> @@ -230,6 +230,59 @@ corresponding stream section.
> Count the number of packets per stream and report it in the
> corresponding stream section.
>
> + at item -read_intervals @var{read_intervals}
> +
> +Read only the specified intervals. @var{read_intervals} must be a
> +sequence of intervals separated by ",".
> +
We can't tell from this if ffprobe is going to seek or just ignore out of
the range. Also, is there any accuracy/behaviour differences between
packets demuxing and frame decoding?
> +Each interval is specified as a time duration specification specifying
> +the interval start (the point to which to seek). If the start seeking
> +point is not specified, no seeking will be performed when reading the
> +corresponding interval.
> +
> +The end seeking point or duration is specified after the optional
"seeking end point"?
> +start point by the "+" or "%" character. In case the "+" character is
> +specified, the leading string is interpreted as the duration of the
> +interval, otherwise as the interval ending position. If the duration
> +specification starts with "#", it is interpreted as a number of
> +packets to read (not including the flushing packets). Otherwise
> +duration or seeking point are parsed as time duration specifications.
> +
> +If no duration or ending point is specified, the program will read
> +until the end of the input.
> +
> +The formal syntax is given by:
> + at example
> + at var{INTERVAL} ::= [@var{START}]([+ at var{DURATION}|%@var{END}])
Sorry, I'm not comfortable with the BNF; what are the ( ) for?
> + at var{INTERVALS} ::= @var{INTERVAL}[, at var{INTERVALS}]
> + at end example
> +
> +For example, the following specification:
"specification" -> "@var{read_intervals}" maybe?
> + at example
> +10+20,01:30%01:45
> + at end example
> +
> +will make ffprobe seek to time 10, read packets in the interval
@command{ffprobe}
> +10-10+20,
"10 to 20 seconds" maybe?
> then read packets from position 01:30 (1 minute and thirty
> +seconds) to position 01:45.
> +
Maybe use some @code{} for the timestamps?
> +To read only 42 frames starting from position 01:23, the following
> +syntax can be used:
> + at example
> +01:23+#42
> + at end example
> +
> +To read just the first 20 seconds, you can use the syntax:
> + at example
> ++20
> + at end example
> +
> +To read until position 02:30 since the input beginning, you can use
> +the syntax:
> + at example
> +%02:30
> + at end example
> +
> @item -show_private_data, -private
> Show private data, that is data depending on the format of the
> particular shown element.
> diff --git a/ffprobe.c b/ffprobe.c
> index 17ec7e2..4ad88a4 100644
> --- a/ffprobe.c
> +++ b/ffprobe.c
> @@ -37,7 +37,9 @@
> #include "libavutil/pixdesc.h"
> #include "libavutil/dict.h"
> #include "libavutil/libm.h"
> +#include "libavutil/parseutils.h"
> #include "libavutil/timecode.h"
> +#include "libavutil/timestamp.h"
> #include "libavdevice/avdevice.h"
> #include "libswscale/swscale.h"
> #include "libswresample/swresample.h"
> @@ -73,6 +75,16 @@ static int show_private_data = 1;
> static char *print_format;
> static char *stream_specifier;
>
> +typedef struct {
> + int64_t start, end, duration; ///< start, end, duration time in microseconds
in AV_TIME_BASE?
> + int has_start, has_end, has_duration;
> + int id; ///< identifier
> + int duration_frames;
> +} ReadInterval;
> +
> +static ReadInterval *read_intervals;
> +static int read_intervals_nb = 0;
> +
> /* section structure definition */
>
> #define SECTION_MAX_NB_CHILDREN 10
> @@ -1593,16 +1605,65 @@ static av_always_inline int process_frame(WriterContext *w,
> return got_frame;
> }
>
> -static void read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
> +static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
> +{
> + av_log(log_ctx, log_level,
> + "id:%d start:%s end:%s ", interval->id,
> + interval->has_start ? av_ts2timestr(interval->start, &AV_TIME_BASE_Q) : "N/A",
> + interval->has_end ? av_ts2timestr(interval->end, &AV_TIME_BASE_Q) : "N/A");
> + if (interval->has_duration && interval->duration_frames)
> + av_log(log_ctx, log_level, "duration:#%"PRId64"\n", interval->duration);
> + else
> + av_log(log_ctx, log_level, "duration:%s\n",
> + interval->has_duration ? av_ts2timestr(interval->duration, &AV_TIME_BASE_Q) : "N/A");
> +}
> +
> +static int read_interval_packets(WriterContext *w, AVFormatContext *fmt_ctx,
> + ReadInterval *interval)
> {
> AVPacket pkt, pkt1;
> AVFrame frame;
> - int i = 0;
> + int ret = 0, i = 0, frame_count = 0;
>
> av_init_packet(&pkt);
>
> + av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
> + log_read_interval(interval, NULL, AV_LOG_VERBOSE);
> +
> + if (interval->has_start) {
> + av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
> + av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
> + if ((ret = av_seek_frame(fmt_ctx, -1, interval->start, AVSEEK_FLAG_BACKWARD)) < 0) {
> + av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64"\n",
> + interval->start);
> + return ret;
You should use the seeking API v2.
Also, there is a frame seek flag IIRC (not sure if it's really implemented
for most formats, but that will be a good way to test it).
> + }
> + }
> +
> while (!av_read_frame(fmt_ctx, &pkt)) {
> if (selected_streams[pkt.stream_index]) {
> + AVRational tb;
> +
> + if (!interval->has_start &&
> + pkt.pts != AV_NOPTS_VALUE) {
> + interval->start = pkt.pts;
> + interval->has_start = 1;
> +
> + if (!interval->has_end) {
> + interval->end = interval->start + interval->duration;
> + interval->has_end = 1;
> + }
> + }
> +
> + tb = fmt_ctx->streams[pkt.stream_index]->time_base;
> + if (interval->has_duration && interval->duration_frames) {
> + if (frame_count >= interval->duration)
> + break;
> + } else if (pkt.pts != AV_NOPTS_VALUE &&
> + av_rescale_q(pkt.pts, tb, AV_TIME_BASE_Q) >= interval->end)
> + break;
> +
> + frame_count++;
> if (do_read_packets) {
> if (do_show_packets)
> show_packet(w, fmt_ctx, &pkt, i++);
[...]
> +static int parse_read_intervals(const char *intervals_spec)
> +{
> + int ret, n, i;
> + char *p, *spec = av_strdup(intervals_spec);
> + if (!spec)
> + return AVERROR(ENOMEM);
> +
> + /* preparse specification, get number of intervals */
> + for (n = 0, p = spec; *p; p++)
> + if (*p == ',')
> + n++;
> + n++;
looks risky if spec=""
[...]
No other comment from me so far.
--
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20130917/2661c385/attachment.asc>
More information about the ffmpeg-devel
mailing list