还是和前文一样,先把架构勾勒出来,后期慢慢讲一下代码流程,可以进行各类网络协议的推流,各类容器的封装
结构体
其实就一些回调函数,看到priv_data_size没,这个指向了AVFormatContext的priv_data
c
typedef struct AVOutputFormat {
const char *name;
/**
* Descriptive name for the format, meant to be more human-readable
* than name. You should use the NULL_IF_CONFIG_SMALL() macro
* to define it.
*/
const char *long_name;
const char *mime_type;
const char *extensions; /**< comma-separated filename extensions */
/* output support */
enum AVCodecID audio_codec; /**< default audio codec */
enum AVCodecID video_codec; /**< default video codec */
enum AVCodecID subtitle_codec; /**< default subtitle codec */
/**
* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER,
* AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS,
* AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH,
* AVFMT_TS_NONSTRICT, AVFMT_TS_NEGATIVE
*/
int flags;
/**
* List of supported codec_id-codec_tag pairs, ordered by "better
* choice first". The arrays are all terminated by AV_CODEC_ID_NONE.
*/
const struct AVCodecTag * const *codec_tag;
const AVClass *priv_class; ///< AVClass for the private context
/*****************************************************************
* No fields below this line are part of the public API. They
* may not be used outside of libavformat and can be changed and
* removed at will.
* New public fields should be added right above.
*****************************************************************
*/
/**
* size of private data so that it can be allocated in the wrapper
*/
int priv_data_size;
/**
* Internal flags. See FF_FMT_FLAG_* in internal.h.
*/
int flags_internal;
int (*write_header)(struct AVFormatContext *);
/**
* Write a packet. If AVFMT_ALLOW_FLUSH is set in flags,
* pkt can be NULL in order to flush data buffered in the muxer.
* When flushing, return 0 if there still is more data to flush,
* or 1 if everything was flushed and there is no more buffered
* data.
*/
int (*write_packet)(struct AVFormatContext *, AVPacket *pkt);
int (*write_trailer)(struct AVFormatContext *);
/**
* A format-specific function for interleavement.
* If unset, packets will be interleaved by dts.
*
* @param s An AVFormatContext for output. pkt will be added to
* resp. taken from its packet buffer.
* @param[in,out] pkt A packet to be interleaved if has_packet is set;
* also used to return packets. If no packet is returned
* (e.g. on error), pkt is blank on return.
* @param flush 1 if no further packets are available as input and
* all remaining packets should be output.
* @param has_packet If set, pkt contains a packet to be interleaved
* on input; otherwise pkt is blank on input.
* @return 1 if a packet was output, 0 if no packet could be output,
* < 0 if an error occurred
*/
int (*interleave_packet)(struct AVFormatContext *s, AVPacket *pkt,
int flush, int has_packet);
/**
* Test if the given codec can be stored in this container.
*
* @return 1 if the codec is supported, 0 if it is not.
* A negative number if unknown.
* MKTAG('A', 'P', 'I', 'C') if the codec is only supported as AV_DISPOSITION_ATTACHED_PIC
*/
int (*query_codec)(enum AVCodecID id, int std_compliance);
void (*get_output_timestamp)(struct AVFormatContext *s, int stream,
int64_t *dts, int64_t *wall);
/**
* Allows sending messages from application to device.
*/
int (*control_message)(struct AVFormatContext *s, int type,
void *data, size_t data_size);
/**
* Write an uncoded AVFrame.
*
* See av_write_uncoded_frame() for details.
*
* The library will free *frame afterwards, but the muxer can prevent it
* by setting the pointer to NULL.
*/
int (*write_uncoded_frame)(struct AVFormatContext *, int stream_index,
AVFrame **frame, unsigned flags);
/**
* Returns device list with it properties.
* @see avdevice_list_devices() for more details.
*/
int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list);
enum AVCodecID data_codec; /**< default data codec */
/**
* Initialize format. May allocate data here, and set any AVFormatContext or
* AVStream parameters that need to be set before packets are sent.
* This method must not write output.
*
* Return 0 if streams were fully configured, 1 if not, negative AVERROR on failure
*
* Any allocations made here must be freed in deinit().
*/
int (*init)(struct AVFormatContext *);
/**
* Deinitialize format. If present, this is called whenever the muxer is being
* destroyed, regardless of whether or not the header has been written.
*
* If a trailer is being written, this is called after write_trailer().
*
* This is called if init() fails as well.
*/
void (*deinit)(struct AVFormatContext *);
/**
* Set up any necessary bitstream filtering and extract any extra data needed
* for the global header.
*
* @note pkt might have been directly forwarded by a meta-muxer; therefore
* pkt->stream_index as well as the pkt's timebase might be invalid.
* Return 0 if more packets from this stream must be checked; 1 if not.
*/
int (*check_bitstream)(struct AVFormatContext *s, struct AVStream *st,
const AVPacket *pkt);
} AVOutputFormat;
操作函数
核心代码其实就三四个
c
/**
* Allocate the stream private data and write the stream header to
* an output media file.
*
* @param s Media file handle, must be allocated with avformat_alloc_context().
* Its oformat field must be set to the desired output format;
* Its pb field must be set to an already opened AVIOContext.
* @param options An AVDictionary filled with AVFormatContext and muxer-private options.
* On return this parameter will be destroyed and replaced with a dict containing
* options that were not found. May be NULL.
*
* @return AVSTREAM_INIT_IN_WRITE_HEADER on success if the codec had not already been fully initialized in avformat_init,
* AVSTREAM_INIT_IN_INIT_OUTPUT on success if the codec had already been fully initialized in avformat_init,
* negative AVERROR on failure.
*
* @see av_opt_find, av_dict_set, avio_open, av_oformat_next, avformat_init_output.
*/
av_warn_unused_result
int avformat_write_header(AVFormatContext *s, AVDictionary **options);
/**
* Allocate the stream private data and initialize the codec, but do not write the header.
* May optionally be used before avformat_write_header to initialize stream parameters
* before actually writing the header.
* If using this function, do not pass the same options to avformat_write_header.
*
* @param s Media file handle, must be allocated with avformat_alloc_context().
* Its oformat field must be set to the desired output format;
* Its pb field must be set to an already opened AVIOContext.
* @param options An AVDictionary filled with AVFormatContext and muxer-private options.
* On return this parameter will be destroyed and replaced with a dict containing
* options that were not found. May be NULL.
*
* @return AVSTREAM_INIT_IN_WRITE_HEADER on success if the codec requires avformat_write_header to fully initialize,
* AVSTREAM_INIT_IN_INIT_OUTPUT on success if the codec has been fully initialized,
* negative AVERROR on failure.
*
* @see av_opt_find, av_dict_set, avio_open, av_oformat_next, avformat_write_header.
*/
av_warn_unused_result
int avformat_init_output(AVFormatContext *s, AVDictionary **options);
/**
* Write a packet to an output media file.
*
* This function passes the packet directly to the muxer, without any buffering
* or reordering. The caller is responsible for correctly interleaving the
* packets if the format requires it. Callers that want libavformat to handle
* the interleaving should call av_interleaved_write_frame() instead of this
* function.
*
* @param s media file handle
* @param pkt The packet containing the data to be written. Note that unlike
* av_interleaved_write_frame(), this function does not take
* ownership of the packet passed to it (though some muxers may make
* an internal reference to the input packet).
* <br>
* This parameter can be NULL (at any time, not just at the end), in
* order to immediately flush data buffered within the muxer, for
* muxers that buffer up data internally before writing it to the
* output.
* <br>
* Packet's @ref AVPacket.stream_index "stream_index" field must be
* set to the index of the corresponding stream in @ref
* AVFormatContext.streams "s->streams".
* <br>
* The timestamps (@ref AVPacket.pts "pts", @ref AVPacket.dts "dts")
* must be set to correct values in the stream's timebase (unless the
* output format is flagged with the AVFMT_NOTIMESTAMPS flag, then
* they can be set to AV_NOPTS_VALUE).
* The dts for subsequent packets passed to this function must be strictly
* increasing when compared in their respective timebases (unless the
* output format is flagged with the AVFMT_TS_NONSTRICT, then they
* merely have to be nondecreasing). @ref AVPacket.duration
* "duration") should also be set if known.
* @return < 0 on error, = 0 if OK, 1 if flushed and there is no more data to flush
*
* @see av_interleaved_write_frame()
*/
int av_write_frame(AVFormatContext *s, AVPacket *pkt);
/**
* Write a packet to an output media file ensuring correct interleaving.
*
* This function will buffer the packets internally as needed to make sure the
* packets in the output file are properly interleaved, usually ordered by
* increasing dts. Callers doing their own interleaving should call
* av_write_frame() instead of this function.
*
* Using this function instead of av_write_frame() can give muxers advance
* knowledge of future packets, improving e.g. the behaviour of the mp4
* muxer for VFR content in fragmenting mode.
*
* @param s media file handle
* @param pkt The packet containing the data to be written.
* <br>
* If the packet is reference-counted, this function will take
* ownership of this reference and unreference it later when it sees
* fit. If the packet is not reference-counted, libavformat will
* make a copy.
* The returned packet will be blank (as if returned from
* av_packet_alloc()), even on error.
* <br>
* This parameter can be NULL (at any time, not just at the end), to
* flush the interleaving queues.
* <br>
* Packet's @ref AVPacket.stream_index "stream_index" field must be
* set to the index of the corresponding stream in @ref
* AVFormatContext.streams "s->streams".
* <br>
* The timestamps (@ref AVPacket.pts "pts", @ref AVPacket.dts "dts")
* must be set to correct values in the stream's timebase (unless the
* output format is flagged with the AVFMT_NOTIMESTAMPS flag, then
* they can be set to AV_NOPTS_VALUE).
* The dts for subsequent packets in one stream must be strictly
* increasing (unless the output format is flagged with the
* AVFMT_TS_NONSTRICT, then they merely have to be nondecreasing).
* @ref AVPacket.duration "duration" should also be set if known.
*
* @return 0 on success, a negative AVERROR on error.
*
* @see av_write_frame(), AVFormatContext.max_interleave_delta
*/
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);
/**
* Write the stream trailer to an output media file and free the
* file private data.
*
* May only be called after a successful call to avformat_write_header.
*
* @param s media file handle
* @return 0 if OK, AVERROR_xxx on error
*/
int av_write_trailer(AVFormatContext *s);
下面这个单独列出来,如果你是想要保存yuv这压根的罗六,可以看看这两个接口
c
/**
* Write an uncoded frame to an output media file.
*
* The frame must be correctly interleaved according to the container
* specification; if not, av_interleaved_write_uncoded_frame() must be used.
*
* See av_interleaved_write_uncoded_frame() for details.
*/
int av_write_uncoded_frame(AVFormatContext *s, int stream_index,
AVFrame *frame);
/**
* Write an uncoded frame to an output media file.
*
* If the muxer supports it, this function makes it possible to write an AVFrame
* structure directly, without encoding it into a packet.
* It is mostly useful for devices and similar special muxers that use raw
* video or PCM data and will not serialize it into a byte stream.
*
* To test whether it is possible to use it with a given muxer and stream,
* use av_write_uncoded_frame_query().
*
* The caller gives up ownership of the frame and must not access it
* afterwards.
*
* @return >=0 for success, a negative code on error
*/
int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index,
AVFrame *frame);
/**
* Test whether a muxer supports uncoded frame.
*
* @return >=0 if an uncoded frame can be written to that muxer and stream,
* <0 if not
*/
int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index);