[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