On Sun, Jun 28, 2015 at 06:55:45PM +0200, wm4 wrote:
[...]
> > Ludmila is working on new tests that involve seeking to more than one
> > place based on wm4's request - from what I understand (not doing any
> > seeking myself) is that ffmpeg.c only seeks once ever. As an API user
> > it's useful to do multiple seeks, testing something not possible in
> > ffmpeg.c. Same goes with draw_horiz_band and I would also like to test
> > other features only available from the API.
> 
> From what I know, ffmpeg.c indeed seeks only once. At least I couldn't
> find out how to make it seek several times in the same file last I
> checked.
> 
> Note that here is a seek test in libavformat/seek-test.c. But what I'd
> like to be tested is whether decoding from start, and seeking back to a
> certain position returns the same result. This tests for example
> whether decoder flushing really resets the the entire decoder state.
> (It often seems to happen that it does, either by design or by
> accident.)

There is also a small code I wrote a while ago that might be helpful. It's
attached to this mail (I didn't take the time to rebase it, but it should
be straightforward).

-- 
Clément B.
From cda6011f4b98515ab27983dc7f5351c037795f88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= <clem...@stupeflix.com>
Date: Thu, 12 Dec 2013 14:54:25 +0100
Subject: [PATCH] WIP: seek/playback fuzz

---
 configure                   |   2 +
 doc/Makefile                |   1 +
 doc/examples/Makefile       |   1 +
 doc/examples/playbackfuzz.c | 333 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 337 insertions(+)
 create mode 100644 doc/examples/playbackfuzz.c

diff --git a/configure b/configure
index 12b2da5..bf8c328 100755
--- a/configure
+++ b/configure
@@ -1315,6 +1315,7 @@ EXAMPLE_LIST="
     metadata_example
     muxing_example
     remuxing_example
+    playbackfuzz_example
     resampling_audio_example
     scaling_video_example
     transcode_aac_example
@@ -2610,6 +2611,7 @@ filtering_video_example_deps="avfilter avcodec avformat avutil"
 metadata_example_deps="avformat avutil"
 muxing_example_deps="avcodec avformat avutil swscale"
 remuxing_example_deps="avcodec avformat avutil"
+playbackfuzz_example_deps="avcodec avformat avutil swresample swscale"
 resampling_audio_example_deps="avutil swresample"
 scaling_video_example_deps="avutil swscale"
 transcode_aac_example_deps="avcodec avformat swresample"
diff --git a/doc/Makefile b/doc/Makefile
index 2502922..e92a826 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -47,6 +47,7 @@ DOC_EXAMPLES-$(CONFIG_FILTERING_VIDEO_EXAMPLE)   += filtering_video
 DOC_EXAMPLES-$(CONFIG_METADATA_EXAMPLE)          += metadata
 DOC_EXAMPLES-$(CONFIG_MUXING_EXAMPLE)            += muxing
 DOC_EXAMPLES-$(CONFIG_REMUXING_EXAMPLE)          += remuxing
+DOC_EXAMPLES-$(CONFIG_PLAYBACKFUZZ_EXAMPLE)      += playbackfuzz
 DOC_EXAMPLES-$(CONFIG_RESAMPLING_AUDIO_EXAMPLE)  += resampling_audio
 DOC_EXAMPLES-$(CONFIG_SCALING_VIDEO_EXAMPLE)     += scaling_video
 DOC_EXAMPLES-$(CONFIG_TRANSCODE_AAC_EXAMPLE)     += transcode_aac
diff --git a/doc/examples/Makefile b/doc/examples/Makefile
index 07251fe..f3a3415 100644
--- a/doc/examples/Makefile
+++ b/doc/examples/Makefile
@@ -20,6 +20,7 @@ EXAMPLES=       avio_reading                       \
                 metadata                           \
                 muxing                             \
                 remuxing                           \
+                playbackfuzz                       \
                 resampling_audio                   \
                 scaling_video                      \
                 transcode_aac                      \
diff --git a/doc/examples/playbackfuzz.c b/doc/examples/playbackfuzz.c
new file mode 100644
index 0000000..c2d20fc
--- /dev/null
+++ b/doc/examples/playbackfuzz.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ * Copyright (c) 2013 Clément Bœsch
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <libavutil/imgutils.h>
+#include <libavutil/timestamp.h>
+#include <libavformat/avformat.h>
+#include <libswresample/swresample.h>
+#include <libswscale/swscale.h>
+
+static AVFormatContext *fmt_ctx = NULL;
+static AVCodecContext *video_dec_ctx = NULL, *audio_dec_ctx;
+static AVStream *video_stream = NULL, *audio_stream = NULL;
+static const char *src_filename = NULL;
+
+static uint8_t *video_dst_data[4] = {NULL};
+static int      video_dst_linesize[4];
+static int video_dst_bufsize;
+
+static int video_stream_idx = -1, audio_stream_idx = -1;
+static AVFrame *frame = NULL;
+static AVPacket pkt;
+static int video_frame_count = 0;
+static int audio_frame_count = 0;
+
+static uint32_t seed_pos  = 0x012345;
+static uint32_t seed_doit = 0x543210;
+static const int max_seeks = 50;
+
+static struct SwsContext *sws_ctx;
+static struct SwrContext *swr_ctx;
+
+static const int                 sws_w         = 320;
+static const int                 sws_h         = 240;
+static const enum AVPixelFormat  sws_pixfmt    = AV_PIX_FMT_RGB24;
+
+static const int64_t             swr_chl       = AV_CH_LAYOUT_STEREO;
+static const enum AVSampleFormat swr_samplefmt = AV_SAMPLE_FMT_S16P;
+static const int                 swr_rate      = 44100;
+
+static int decode_packet(int *got_frame, int cached)
+{
+    int ret = 0;
+    int decoded = pkt.size;
+
+    *got_frame = 0;
+
+    if (pkt.stream_index == video_stream_idx) {
+        ret = avcodec_decode_video2(video_dec_ctx, frame, got_frame, &pkt);
+        if (ret < 0) {
+            fprintf(stderr, "Error decoding video frame\n");
+            return ret;
+        }
+        decoded = FFMIN(ret, pkt.size);
+
+        if (*got_frame) {
+            int64_t ts = av_frame_get_best_effort_timestamp(frame);
+            ret = sws_scale(sws_ctx, (const uint8_t **)frame->data, frame->linesize,
+                            0, frame->height, video_dst_data, video_dst_linesize);
+            if (ret < 0) {
+                fprintf(stderr, "Unable to scale frame\n");
+                return ret;
+            }
+            printf("[V:%04d] [%s] decoded and scaled frame\n", video_frame_count++, av_ts2str(ts));
+
+        }
+    } else if (pkt.stream_index == audio_stream_idx) {
+        ret = avcodec_decode_audio4(audio_dec_ctx, frame, got_frame, &pkt);
+        if (ret < 0) {
+            fprintf(stderr, "Error decoding audio frame\n");
+            return ret;
+        }
+        decoded = FFMIN(ret, pkt.size);
+
+        if (*got_frame) {
+            uint8_t **output;
+            int out_samples, nb_out;
+            int64_t ts = av_frame_get_best_effort_timestamp(frame);
+
+            out_samples = av_rescale_rnd(swr_get_delay(swr_ctx, swr_rate) + frame->nb_samples,
+                                         frame->sample_rate, swr_rate, AV_ROUND_UP);
+            ret = av_samples_alloc_array_and_samples(&output, NULL,
+                                                     av_get_channel_layout_nb_channels(swr_chl),
+                                                     out_samples, swr_samplefmt, 0);
+            if (ret < 0) {
+                fprintf(stderr, "Unable to allocate resampled buffer\n");
+                return ret;
+            }
+
+            nb_out = swr_convert(swr_ctx, output, out_samples,
+                                 (const unsigned char **)frame->extended_data,
+                                 frame->nb_samples);
+            printf("[A:%04d] [%s] decoded and converted %d to %d samples, got %d\n",
+                   audio_frame_count++, av_ts2str(ts),
+                   frame->nb_samples, out_samples, nb_out);
+
+            av_freep(&output[0]);
+            av_freep(&output);
+        }
+    }
+
+    av_frame_unref(frame);
+
+    return decoded;
+}
+
+static int open_codec_context(int *stream_idx,
+                              AVFormatContext *fmt_ctx, enum AVMediaType type)
+{
+    int ret;
+    AVStream *st;
+    AVCodecContext *dec_ctx = NULL;
+    AVCodec *dec = NULL;
+    AVDictionary *opts = NULL;
+
+    ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
+    if (ret < 0) {
+        fprintf(stderr, "Could not find %s stream in input file '%s'\n",
+                av_get_media_type_string(type), src_filename);
+        return ret;
+    } else {
+        *stream_idx = ret;
+        st = fmt_ctx->streams[*stream_idx];
+
+        dec_ctx = st->codec;
+        dec = avcodec_find_decoder(dec_ctx->codec_id);
+        if (!dec) {
+            fprintf(stderr, "Failed to find %s codec\n",
+                    av_get_media_type_string(type));
+            return ret;
+        }
+
+        av_dict_set(&opts, "refcounted_frames", "1", 0);
+        if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) {
+            fprintf(stderr, "Failed to open %s codec\n",
+                    av_get_media_type_string(type));
+            return ret;
+        }
+    }
+
+    return 0;
+}
+
+int main (int argc, char **argv)
+{
+    int ret = 0, got_frame, nb_seek = 0;
+    const char *src_filename;
+
+    if (argc != 2) {
+        printf("Usage: %s <file>\n", argv[0]);
+        return 0;
+    }
+    src_filename = argv[1];
+
+    av_register_all();
+
+    if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
+        fprintf(stderr, "Could not open source file %s\n", src_filename);
+        return 1;
+    }
+
+    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
+        fprintf(stderr, "Could not find stream information\n");
+        return 1;
+    }
+
+    if (fmt_ctx->duration <= 0) {
+        fprintf(stderr, "Format has no duration, can't randomly seek\n");
+        return 1;
+    }
+
+    if (open_codec_context(&video_stream_idx, fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) {
+        video_stream = fmt_ctx->streams[video_stream_idx];
+        video_dec_ctx = video_stream->codec;
+
+        ret = av_image_alloc(video_dst_data, video_dst_linesize,
+                             sws_w, sws_h, sws_pixfmt, 1);
+        if (ret < 0) {
+            fprintf(stderr, "Could not allocate raw video buffer\n");
+            goto end;
+        }
+        video_dst_bufsize = ret;
+
+        sws_ctx = sws_getContext(video_dec_ctx->width, video_dec_ctx->height,
+                                 video_dec_ctx->pix_fmt,
+                                 sws_w, sws_h, sws_pixfmt,
+                                 SWS_BILINEAR, NULL, NULL, NULL);
+        if (!sws_ctx) {
+            fprintf(stderr, "Could not allocate scaling context\n");
+            ret = AVERROR(EINVAL);
+            goto end;
+        }
+    }
+
+#if 0
+    if (open_codec_context(&audio_stream_idx, fmt_ctx, AVMEDIA_TYPE_AUDIO) >= 0) {
+        audio_stream = fmt_ctx->streams[audio_stream_idx];
+        audio_dec_ctx = audio_stream->codec;
+
+        swr_ctx = swr_alloc_set_opts(NULL, swr_chl, swr_samplefmt, swr_rate,
+                                     audio_dec_ctx->channel_layout,
+                                     audio_dec_ctx->sample_fmt,
+                                     audio_dec_ctx->sample_rate,
+                                     0, NULL);
+        if (!swr_ctx) {
+            fprintf(stderr, "Could not allocate resampler context\n");
+            ret = AVERROR(ENOMEM);
+            goto end;
+        }
+
+        if ((ret = swr_init(swr_ctx)) < 0) {
+            fprintf(stderr, "Failed to initialize the resampling context\n");
+            goto end;
+        }
+    }
+#endif
+
+    av_dump_format(fmt_ctx, 0, src_filename, 0);
+
+    if (!audio_stream && !video_stream) {
+        fprintf(stderr, "Could not find audio or video stream in the input, aborting\n");
+        ret = 1;
+        goto end;
+    }
+
+    frame = av_frame_alloc();
+    if (!frame) {
+        fprintf(stderr, "Could not allocate frame\n");
+        ret = AVERROR(ENOMEM);
+        goto end;
+    }
+
+    for (;;) {
+        av_init_packet(&pkt);
+        pkt.data = NULL;
+        pkt.size = 0;
+
+        while (av_read_frame(fmt_ctx, &pkt) >= 0) {
+            AVPacket orig_pkt = pkt;
+            do {
+                seed_doit = seed_doit*1664525+1013904223;
+                if (seed_doit < UINT32_MAX/100) {
+                    int64_t ts, mints, maxts;
+                    const char *direction;
+
+                    if (nb_seek == max_seeks)
+                        goto flush;
+                    nb_seek++;
+
+                    seed_pos = seed_pos*1664525+1013904223;
+                    ts = seed_pos / (float)(1LL<<32) * fmt_ctx->duration;
+
+                    if (seed_doit & 1) {
+                        direction = "backward";
+                        mints = INT64_MIN;
+                        maxts = ts;
+                    } else {
+                        direction = "forward";
+                        mints = ts;
+                        maxts = INT64_MAX;
+                    }
+                    printf("seek (%d/%d) %s at ~%.1f%%\n", nb_seek, max_seeks,
+                           direction, ts / (float)fmt_ctx->duration * 100.);
+                    ret = avformat_seek_file(fmt_ctx, -1, mints, ts, maxts, 0);
+                    if (ret < 0)
+                        printf("seek failed (%s)\n", av_err2str(ret));
+                    avcodec_flush_buffers(video_dec_ctx);
+
+#if 0
+                    if ((ret = swr_init(swr_ctx)) < 0) {
+                        fprintf(stderr, "Failed to reset the resampling context\n");
+                        goto end;
+                    }
+#endif
+
+                    av_init_packet(&pkt);
+                    pkt.data = NULL;
+                    pkt.size = 0;
+                    break;
+                }
+                ret = decode_packet(&got_frame, 0);
+                if (ret < 0)
+                    break;
+                pkt.data += ret;
+                pkt.size -= ret;
+            } while (pkt.size > 0);
+            av_free_packet(&orig_pkt);
+        }
+
+        printf(" ==> seek back to the beginning\n");
+        ret = avformat_seek_file(fmt_ctx, -1, INT64_MIN, 0, INT64_MAX, 0);
+        if (ret < 0) {
+            printf("Unable to seek to start position\n");
+            break;
+        }
+    }
+
+flush:
+    pkt.data = NULL;
+    pkt.size = 0;
+    do {
+        decode_packet(&got_frame, 1);
+    } while (got_frame);
+
+end:
+    swr_free(&swr_ctx);
+    avcodec_close(video_dec_ctx);
+    avcodec_close(audio_dec_ctx);
+    avformat_close_input(&fmt_ctx);
+    av_frame_free(&frame);
+    av_free(video_dst_data[0]);
+
+    return ret < 0;
+}
-- 
2.4.4

Attachment: pgpw8ZJi4QDwZ.pgp
Description: PGP signature

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to