[FFmpeg-devel] [PATCH] doc/examples: add avio_writing examples

Stefano Sabatini stefasab at gmail.com
Wed Nov 5 18:35:18 CET 2014


Show how to use the AVIO writing API.
---
 .gitignore                  |   1 +
 configure                   |   1 +
 doc/examples/Makefile       |   1 +
 doc/examples/avio_writing.c | 225 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 228 insertions(+)
 create mode 100644 doc/examples/avio_writing.c

diff --git a/.gitignore b/.gitignore
index 793d33a..628ffb1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,7 @@
 /doc/avoptions_format.texi
 /doc/doxy/html/
 /doc/examples/avio_reading
+/doc/examples/avio_writing
 /doc/examples/decoding_encoding
 /doc/examples/demuxing_decoding
 /doc/examples/extract_mvs
diff --git a/configure b/configure
index 570878d..5b3a246 100755
--- a/configure
+++ b/configure
@@ -1310,6 +1310,7 @@ COMPONENT_LIST="
 
 EXAMPLE_LIST="
     avio_reading_example
+    avio_writing_example
     decoding_encoding_example
     demuxing_decoding_example
     extract_mvs_example
diff --git a/doc/examples/Makefile b/doc/examples/Makefile
index 07251fe..ad10b5b 100644
--- a/doc/examples/Makefile
+++ b/doc/examples/Makefile
@@ -12,6 +12,7 @@ CFLAGS := $(shell pkg-config --cflags $(FFMPEG_LIBS)) $(CFLAGS)
 LDLIBS := $(shell pkg-config --libs $(FFMPEG_LIBS)) $(LDLIBS)
 
 EXAMPLES=       avio_reading                       \
+                avio_writing                       \
                 decoding_encoding                  \
                 demuxing_decoding                  \
                 extract_mvs                        \
diff --git a/doc/examples/avio_writing.c b/doc/examples/avio_writing.c
new file mode 100644
index 0000000..27ef21a
--- /dev/null
+++ b/doc/examples/avio_writing.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2014 Stefano Sabatini
+ *
+ * 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.
+ */
+
+/**
+ * @file
+ * libavformat AVIOContext API example.
+ *
+ * Make libavformat demuxer access media content through a custom
+ * AVIOContext write callback.
+ * @example avio_writing.c
+ */
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavformat/avio.h>
+#include <libavutil/file.h>
+#include <libavutil/timestamp.h>
+
+struct buffer_data {
+    uint8_t *buf;
+    size_t size;
+    uint8_t *ptr;
+    size_t room; ///< size left in the buffer
+};
+
+static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
+{
+    AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
+
+    printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
+           tag,
+           av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
+           av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
+           av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
+           pkt->stream_index);
+}
+
+static int write_packet(void *opaque, uint8_t *buf, int buf_size)
+{
+    struct buffer_data *bd = (struct buffer_data *)opaque;
+    while (buf_size > bd->room) {
+        int64_t offset = bd->ptr - bd->buf;
+        bd->buf = av_realloc_f(bd->buf, 2, bd->size);
+        if (!bd->buf)
+            return AVERROR(ENOMEM);
+        bd->size *= 2;
+        bd->ptr = bd->buf + offset;
+        bd->room = bd->size - offset;
+    }
+    printf("write packet pkt_size:%d used_buf_size:%zu buf_size:%zu buf_room:%zu\n", buf_size, bd->ptr-bd->buf, bd->size, bd->room);
+
+    /* copy buffer data to buffer_data buffer */
+    memcpy(bd->ptr, buf, buf_size);
+    bd->ptr  += buf_size;
+    bd->room -= buf_size;
+
+    return buf_size;
+}
+
+int main(int argc, char *argv[])
+{
+    AVFormatContext *ifmt_ctx = NULL;
+    AVFormatContext *ofmt_ctx = NULL;
+    AVIOContext *avio_ctx = NULL;
+    uint8_t *avio_ctx_buffer = NULL;
+    size_t avio_ctx_buffer_size = 4096;
+    char *in_filename = NULL;
+    char *out_filename = NULL;
+    int i, ret = 0;
+    struct buffer_data bd = { 0 };
+    const size_t bd_buf_size = 1024;
+    AVPacket pkt;
+
+    if (argc != 3) {
+        fprintf(stderr, "usage: %s input_file output_file\n"
+                "API example program to show how to write to a custom buffer "
+                "accessed through AVIOContext.\n"
+                "Remux the content of input_file to output_file, writing to a custom buffer.\n"
+                "The output file must support the same codec as the input file.\n", argv[0]);
+        return 1;
+    }
+    in_filename  = argv[1];
+    out_filename = argv[2];
+
+    av_register_all();
+
+    if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
+        fprintf(stderr, "Could not open input file '%s'", in_filename);
+        goto end;
+    }
+
+    if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
+        fprintf(stderr, "Failed to retrieve input stream information");
+        goto end;
+    }
+
+    av_dump_format(ifmt_ctx, 0, in_filename, 0);
+
+    /* fill opaque structure used by the AVIOContext write callback */
+    bd.ptr  = bd.buf = av_malloc(bd_buf_size);
+    if (!bd.buf) {
+        ret = AVERROR(ENOMEM);
+        goto end;
+    }
+    bd.size = bd.room = bd_buf_size;
+
+    avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
+    if (!avio_ctx_buffer) {
+        ret = AVERROR(ENOMEM);
+        goto end;
+    }
+    avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
+                                  1, &bd, NULL, &write_packet, NULL);
+    if (!avio_ctx) {
+        ret = AVERROR(ENOMEM);
+        goto end;
+    }
+
+    ret = avformat_alloc_output_context2(&ofmt_ctx, NULL, "mpegts", NULL);
+    if (ret < 0) {
+        fprintf(stderr, "Could not create output context\n");
+        goto end;
+    }
+    ofmt_ctx->pb = avio_ctx;
+
+    for (i = 0; i < ifmt_ctx->nb_streams; i++) {
+        AVStream *in_stream = ifmt_ctx->streams[i];
+        AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
+        if (!out_stream) {
+            fprintf(stderr, "Failed creating output stream\n");
+            ret = AVERROR_UNKNOWN;
+            goto end;
+        }
+
+        ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
+        if (ret < 0) {
+            fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
+            goto end;
+        }
+        out_stream->codec->codec_tag = 0;
+        if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
+            out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
+    }
+    av_dump_format(ofmt_ctx, 0, out_filename, 1);
+
+    ret = avformat_write_header(ofmt_ctx, NULL);
+    if (ret < 0) {
+        fprintf(stderr, "Error occurred when opening output file\n");
+        goto end;
+    }
+
+    while (1) {
+        AVStream *in_stream, *out_stream;
+
+        ret = av_read_frame(ifmt_ctx, &pkt);
+        if (ret < 0)
+            break;
+
+        in_stream  = ifmt_ctx->streams[pkt.stream_index];
+        out_stream = ofmt_ctx->streams[pkt.stream_index];
+        log_packet(ifmt_ctx, &pkt, "in");
+
+        /* copy packet */
+        av_packet_rescale_ts(&pkt, in_stream->time_base, out_stream->time_base);
+        pkt.pos = -1;
+        log_packet(ofmt_ctx, &pkt, "out");
+
+        ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
+        if (ret < 0) {
+            fprintf(stderr, "Error muxing packet\n");
+            break;
+        }
+        av_free_packet(&pkt);
+    }
+
+    av_write_trailer(ofmt_ctx);
+end:
+
+    avformat_close_input(&ifmt_ctx);
+
+    /* close output */
+    avformat_free_context(ofmt_ctx);
+    av_freep(&avio_ctx->buffer);
+    av_free(avio_ctx);
+
+    /* write buffer to file */
+    {
+        FILE *out_file = fopen(out_filename, "w");
+        if (!out_file) {
+            fprintf(stderr, "Could not open file '%s'\n", out_filename);
+            ret = AVERROR(errno);
+        } else {
+            fwrite(bd.buf, bd.size, 1, out_file);
+            fclose(out_file);
+        }
+    }
+
+    av_free(bd.buf);
+
+    if (ret < 0 && ret != AVERROR_EOF) {
+        fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
+        return 1;
+    }
+
+    return 0;
+}
-- 
1.8.3.2



More information about the ffmpeg-devel mailing list