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
signature.asc
Description: Digital signature
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel