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

Nicolas George george at nsup.org
Thu Nov 6 20:45:53 CET 2014


Le quintidi 15 brumaire, an CCXXIII, Stefano Sabatini a écrit :
> 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

s/demuxer/muxer/?

> + * 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);
> +}

Is it really useful for the example?

> +
> +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;
> +    }

The input part, is it really necessary for the usefulness of the example? We
already have demuxing examples and muxing examples, so I think an example
about custom AVIO contexts could be underdeveloped in that regard: just
write synthetic sound to a WAVE file or something.

> +    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;
> +}

Regards,

-- 
  Nicolas George
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20141106/63688063/attachment.asc>


More information about the ffmpeg-devel mailing list