[FFmpeg-devel] [PATCH 5/5] lavd: add uncoded_frame test program.

Nicolas George george at nsup.org
Tue Feb 4 15:44:34 CET 2014


Signed-off-by: Nicolas George <george at nsup.org>
---
 libavdevice/Makefile        |   3 +-
 libavdevice/uncoded_frame.c | 255 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 257 insertions(+), 1 deletion(-)
 create mode 100644 libavdevice/uncoded_frame.c


A bit long for what it does, but I was not comfortable leaving the feature
without test program in the code base. Could probably have been slightly
shorter using lavfi/movie, but that would make another library in the mix.


diff --git a/libavdevice/Makefile b/libavdevice/Makefile
index fb57c33..ffdfa37 100644
--- a/libavdevice/Makefile
+++ b/libavdevice/Makefile
@@ -62,4 +62,5 @@ SKIPHEADERS-$(CONFIG_V4L2_OUTDEV)        += v4l2-common.h
 SKIPHEADERS-$(HAVE_ALSA_ASOUNDLIB_H)     += alsa-audio.h
 SKIPHEADERS-$(HAVE_SNDIO_H)              += sndio_common.h
 
-TESTPROGS = timefilter
+TESTPROGS = timefilter                                                  \
+            uncoded_frame
diff --git a/libavdevice/uncoded_frame.c b/libavdevice/uncoded_frame.c
new file mode 100644
index 0000000..f827d37
--- /dev/null
+++ b/libavdevice/uncoded_frame.c
@@ -0,0 +1,255 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libavformat/avformat.h"
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "avdevice.h"
+
+typedef struct {
+    AVCodec *decoder_codec;
+    AVStream *st_in;
+    AVStream *st_out;
+    AVFormatContext *mux;
+    char *dev_name;
+    int64_t frame_no;
+    int idx_in;
+    int mux_same;
+} Stream;
+
+int main(int argc, char **argv)
+{
+    char *input_file;
+    AVFormatContext *demux = NULL;
+    Stream streams[2] = { { 0 } };
+    AVPacket packet;
+    AVFrame *frame = NULL;
+    int nb_streams, i, got_frame, ret = 0;
+    int64_t pts;
+
+    if (argc < 3 || argc > 4) {
+        av_log(NULL, AV_LOG_ERROR, "Usage: %s input out [out2]\n",
+               argv[0]);
+        exit(1);
+    }
+    input_file = argv[1];
+    streams[0].dev_name = argv[2];
+    streams[1].dev_name = argv[argc >= 4 ? 3 : 2];
+
+    av_register_all();
+    avdevice_register_all();
+    if ((ret = avformat_open_input(&demux, input_file, NULL, NULL)) < 0) {
+        av_log(NULL, AV_LOG_ERROR, "Failed to read '%s': %s\n",
+               input_file, av_err2str(ret));
+        goto fail;
+    }
+    if ((ret = avformat_find_stream_info(demux, NULL)) < 0) {
+        av_log(demux, AV_LOG_ERROR, "Failed to find streams: %s\n",
+               av_err2str(ret));
+        goto fail;
+    }
+
+    streams[0].idx_in = av_find_best_stream(demux, AVMEDIA_TYPE_VIDEO, -1, -1,
+                                            &streams[0].decoder_codec, 0);
+    streams[1].idx_in = av_find_best_stream(demux, AVMEDIA_TYPE_AUDIO, -1,
+                                            streams[0].idx_in,
+                                            &streams[1].decoder_codec, 0);
+    if (streams[0].idx_in < 0 && streams[1].idx_in < 0) {
+        ret = streams[0].idx_in;
+        av_log(demux, AV_LOG_ERROR, "No playable stream found: %s / %s\n",
+               av_err2str(streams[0].idx_in), av_err2str(streams[1].idx_in));
+        goto fail;
+    }
+    for (i = 0; i < demux->nb_streams; i++)
+        demux->streams[i]->discard = AVDISCARD_ALL;
+    for (i = 0; i < 2; i++)
+        if (streams[i].idx_in >= 0)
+            streams[i].st_in = demux->streams[streams[i].idx_in];
+    nb_streams = 2;
+    if (!streams[0].st_in)
+        FFSWAP(Stream, streams[0], streams[1]);
+    if (!streams[1].st_in)
+        nb_streams = 1;
+    av_log(demux, AV_LOG_INFO,
+           "Using streams %d and %d to devices '%s' and '%s'\n",
+           streams[0].idx_in, FFMAX(streams[1].idx_in, -1),
+           streams[0].dev_name,
+           !streams[1].st_in ? "none" :
+           streams[1].dev_name == streams[0].dev_name ? "same" :
+           streams[1].dev_name);
+
+    /* Open decoders */
+    for (i = 0; i < nb_streams; i++) {
+        Stream *s = &streams[i];
+        s->st_in->discard = 0;
+        ret = avcodec_open2(s->st_in->codec, s->decoder_codec, NULL);
+        if (ret < 0) {
+            av_log(demux, AV_LOG_ERROR, "Failed to open decoder #%d: %s\n",
+                   i, av_err2str(ret));
+            goto fail;
+        }
+        av_opt_set_int(s->st_in->codec, "refcounted_frames", 1, 0);
+    }
+
+    /* Create output devices */
+    for (i = 0; i < nb_streams; i++) {
+        Stream *s = &streams[i];
+        char *fmt = NULL, *dev = s->dev_name;
+        if (i && dev == streams[0].dev_name) {
+            s->mux = streams[0].mux;
+            s->mux_same = 1;
+        } else {
+            if ((dev = strchr(dev, ':'))) {
+                *(dev++) = 0;
+                fmt = s->dev_name;
+            }
+            ret = avformat_alloc_output_context2(&s->mux, NULL, fmt, dev);
+            if (ret < 0) {
+                av_log(NULL, AV_LOG_ERROR, "Failed to allocate output '%s'\n",
+                       av_err2str(ret));
+                goto fail;
+            }
+            if (!(s->mux->oformat->flags & AVFMT_NOFILE)) {
+                ret = avio_open2(&s->mux->pb, s->mux->filename, AVIO_FLAG_WRITE,
+                                 NULL, NULL);
+                if (ret < 0) {
+                    av_log(s->mux, AV_LOG_ERROR, "Failed to init output: %s\n",
+                           av_err2str(ret));
+                    goto fail;
+                }
+            }
+        }
+    }
+
+    /* Create output device streams */
+    for (i = 0; i < nb_streams; i++) {
+        Stream *s = &streams[i];
+        if (!(s->st_out = avformat_new_stream(s->mux, NULL))) {
+            ret = AVERROR(ENOMEM);
+            av_log(NULL, AV_LOG_ERROR, "Failed to create output stream\n");
+            goto fail;
+        }
+        s->st_out->time_base = s->st_in->time_base;
+        ret = avcodec_copy_context(s->st_out->codec, s->st_in->codec);
+        if (ret < 0) {
+            av_log(NULL, AV_LOG_ERROR, "Error copying stream parameters: %s\n",
+                   av_err2str(ret));
+            goto fail;
+        }
+        switch (s->st_in->codec->codec_type) {
+        case AVMEDIA_TYPE_VIDEO:
+            s->st_out->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+            s->st_out->avg_frame_rate = s->st_in->avg_frame_rate;
+            s->st_out->  r_frame_rate = s->st_in->  r_frame_rate;
+            break;
+        case AVMEDIA_TYPE_AUDIO:
+            s->st_out->codec->codec_id =
+                av_get_pcm_codec(s->st_out->codec->sample_fmt, -1);
+            break;
+        default:
+            av_assert0(!"reached");
+        }
+    }
+
+    /* Init output devices */
+    for (i = 0; i < nb_streams; i++) {
+        Stream *s = &streams[i];
+        if (s->mux_same)
+            continue;
+        if ((ret = avformat_write_header(s->mux, NULL)) < 0) {
+            av_log(s->mux, AV_LOG_ERROR, "Failed to init output: %s\n",
+                   av_err2str(ret));
+            goto fail;
+        }
+    }
+
+    /* Check output devices */
+    for (i = 0; i < nb_streams; i++) {
+        Stream *s = &streams[i];
+        ret = av_write_uncoded_frame_query(s->mux, s->st_out->index);
+        if (ret < 0) {
+            av_log(s->mux, AV_LOG_ERROR,
+                   "Uncoded frames not supported on stream #%d: %s\n",
+                   i, av_err2str(ret));
+            goto fail;
+        }
+    }
+
+    while (1) {
+        if ((ret = av_read_frame(demux, &packet)) < 0) {
+            if (ret == AVERROR_EOF) {
+                ret = 0;
+                break;
+            }
+            av_log(demux, AV_LOG_ERROR, "Error reading: %s\n",
+                   av_err2str(ret));
+        }
+        for (i = 0; i < nb_streams; i++) {
+            Stream *s = &streams[i];
+            if (packet.stream_index != s->idx_in)
+                continue;
+            if (!frame && !(frame = av_frame_alloc())) {
+                ret = AVERROR(ENOMEM);
+                av_log(NULL, AV_LOG_ERROR, "Could not allocate frame\n");
+                goto fail;
+            }
+            switch (s->st_in->codec->codec_type) {
+            case AVMEDIA_TYPE_VIDEO:
+                ret = avcodec_decode_video2(s->st_in->codec, frame,
+                                            &got_frame, &packet);
+                break;
+            case AVMEDIA_TYPE_AUDIO:
+                ret = avcodec_decode_audio4(s->st_in->codec, frame,
+                                            &got_frame, &packet);
+                break;
+            default:
+                av_assert0(!"reached");
+            }
+            if (ret < 0) {
+                av_log(s->st_in->codec, AV_LOG_ERROR, "Error decoding: %s\n",
+                       av_err2str(ret));
+                goto fail;
+            }
+            if (!got_frame)
+                continue;
+            pts = av_frame_get_best_effort_timestamp(frame);
+            frame->pts = pts == AV_NOPTS_VALUE ?
+                av_rescale_q(s->frame_no,
+                             av_inv_q(s->st_out->avg_frame_rate),
+                             s->st_out->time_base) :
+                av_rescale_q_rnd(pts,
+                                 demux->streams[packet.stream_index]->time_base,
+                                 s->st_out->time_base,
+                    AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
+            ret = av_interleaved_write_uncoded_frame(s->mux, s->st_out->index,
+                                                     frame);
+            if (ret < 0) {
+                av_log(s->st_out->codec, AV_LOG_ERROR,
+                       "Error writing frame: %s\n", av_err2str(ret));
+                goto fail;
+            }
+            frame = NULL;
+            s->frame_no++;
+        }
+        av_free_packet(&packet);
+    }
+
+    for (i = 0; i < nb_streams; i++) {
+        Stream *s = &streams[i];
+        if (!s->mux_same)
+            av_write_trailer(s->mux);
+    }
+
+fail:
+    for (i = 0; i < nb_streams; i++) {
+        Stream *s = &streams[i];
+        avcodec_close(s->st_in->codec);
+        if (!s->mux_same) {
+            if (s->mux->pb)
+                avio_close(s->mux->pb);
+            avformat_free_context(s->mux);
+        }
+    }
+    avformat_close_input(&demux);
+    return ret < 0;
+}
-- 
1.8.5.3



More information about the ffmpeg-devel mailing list