Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/shootingking-am/ffmpeg-pseudocode-tutorial
A brief understanding of ffmpeg cli through pseudocode
https://github.com/shootingking-am/ffmpeg-pseudocode-tutorial
ffmpeg libav pseudocode tutorial
Last synced: 3 months ago
JSON representation
A brief understanding of ffmpeg cli through pseudocode
- Host: GitHub
- URL: https://github.com/shootingking-am/ffmpeg-pseudocode-tutorial
- Owner: ShootingKing-AM
- Created: 2020-12-19T04:32:15.000Z (about 4 years ago)
- Default Branch: master
- Last Pushed: 2020-12-20T17:04:10.000Z (about 4 years ago)
- Last Synced: 2024-02-29T11:32:30.028Z (11 months ago)
- Topics: ffmpeg, libav, pseudocode, tutorial
- Language: HTML
- Homepage:
- Size: 808 KB
- Stars: 9
- Watchers: 4
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# FFmpeg/libav Pseudocode Tutorial
A broad workflow understanding of ffmpeg-cli through loose pseudocode.FFmpeg-cli source from [github/FFmpeg](https://github.com/FFmpeg/FFmpeg#ffmpeg-readme), Dec'2020 - [Tree](https://github.com/FFmpeg/FFmpeg/tree/001bc594d82f3df67a6e96c6ea022f4e39002385)
## Rationale
[FFmpeg](http://ffmpeg.org/about.html) is a collection of libraries and includes a command-line-interface(*cli*) tool to **manipulate, convert and stream multimedia** content.The goal of understanding ffmpeg-cli is to be able to to integrate FFmpeg into our projects without having to call the ffmpeg-cli in background to do multimedia operation. This is important because,
1. Starting up an external executable tends to be blocked by antivirus software and can cause issues with users.
2. Optimize your project specific libav usage and skip unnecessary code from ffmpeg-cliAlso, ffmpeg official documentation being vague at best, the only option for developers looking to implement ffmpeg's libraries (`libav`) functionality into their code is to read the command line interface's source code.
Reading ffmpeg-cli's source code is very hard, because its not meant to be used as a study material for understanding how to use `libav` but as a optimized multimedia tool. Hence, i tried to straighten out its source code into simple pseudocode function highlighting **when and where** to call important(almost all) libav's functions, for an overall broader picture of ffmpeg workflow. For information regarding **how** to call a `libav` function call, one can refer to the [doxygen documentation](https://ffmpeg.org/doxygen/4.1/index.html) and [ffmpeg-cli-source files](https://github.com/FFmpeg/FFmpeg/tree/master/fftools).
Lack of tutorials in this regard compelled me to open-source this document.
## How to read through Pseudocode
1. This pseudocode, assumes you have basic multimedia knowledge and ffmpeg internal structure. (if not head over to this [picture tutorial](https://github.com/leandromoreira/ffmpeg-libav-tutorial/blob/master/README.md)).
2. This pseudocode also assumes you have basic understanding of C(++) functions.
3. The `syntactical rules` of the following pseudocode are,**a.** There are `two sets` of functions,
i. `Standard library calls`, those are available in *libav* headers(, .libs, .dlls), and
ii. `ffmpeg-cli specific functions`(non-std functions), these should be understood and should be implemented in your specific project.
`Non-std` function have been named as `::()` in pseudocode, so that you can refer to those specific source files to get the exact working.
`Std` function just have `()` and usually start with `av*`
**b.** Each tab indicates that the upcoming function call(s) is/are inside the above function call. For example,
```swift
foo()
bar()
```
This means `bar()` function call is inside `foo()` function and `bar()` is being called by `foo()`.
**c.** `//` indicates there is code which does *something* in place of this comment.
`/**/` Indicates a comment which explains the following code.
`///` Indicates just a comment.
### ffmpeg-cli Pseudocode
Syntax highlighted pseudocode - [Here](https://github.com/ShootingKing-AM/ffmpeg-psedocode-tutorial/blob/master/pseudoCode.swift)Functions linked to Doxygen ffmpeg documentation. (Click to Refer).
main()
cmdutils.c::init_dynload()
SetDllDirectory("")register_exit()
ffmpeg.c::ffmpeg_cleanup()
// Free filers FilterGraph with avfilter_graph_free()
// for each FilterGraph's Input
av_fifo_generic_read()
av_frame_free()
av_fifo_freep()
avsubtitle_free()
av_buffer_unref()
av_freep()
avfilter_inout_free()// Close Files with avio_closep()
avformat_free_context()
av_dict_free()
av_freep()// Close Output Streams av_bsf_free()
av_frame_free()
av_frame_free()
av_dict_free()av_freep()
av_expr_free()
av_freep()avcodec_free_context()
avcodec_parameters_free()av_fifo_generic_read(muxing_queue, &pkt)
av_packet_unref(&pkt)
av_fifo_freep(muxing_queue)free_input_threads()
// Close input Files avformat_close_input()
av_freep()// Close input Streams
av_frame_free(decoded_frame)
av_frame_free(filter_frame)
av_dict_free(decoder_opts)
avsubtitle_freesubtitle)
av_frame_free(sub2video.frame)
av_freep(filters)
av_freep(hwaccel_device)
av_freep(dts_buffer)
avcodec_free_context(dec_ctx)
av_freep(input_streams)// if CONFIG_AVDEVICE set avdevice_register_all();
ffmpeg_opt.c::ffmpeg_parse_options()
options = cmdutils.c::split_commandline() /* split the commandline into an internal representation */
cmdutils.c::prepare_app_arguments() /* perform system-dependent conversions for arguments list */
cmdutils.c::init_parse_context()
cmdutils.c::init_opts()
av_dict_set()
cmdutils.c::parse_optgroup("GLOABAL")cmdutils.c::open_files()
ffmpeg_opt.c::open_input_file()
// Check if supported file format with
libavformat::av_find_input_format()
inputContext = libavformat::avformat_alloc_context()
av_dict_set_int() /* Setting global Opts as per Input file opts */
find_codec_or_die()
avcodec_find_encoder_by_name()
// Set inputContext's members as per codec
libavformat::avformat_open_input()
libavformat::avformat_find_stream_info()
// if specified in cmd line options, avformat_seek_file()
ffmpeg_opt.c::add_input_streams()/* Add all the streams from the given input file to the global list of input streams. */
dec_Context = avcodec_alloc_context3()
avcodec_parameters_to_context(dec_Context, cmdLineParameters)
// Based on Codec_Type (VID, AUD, SUB, etc, etc)
VID:
avcodec_find_decoder()
// Specific to HwAccelearation
av_get_pix_fmt()
av_hwdevice_find_type_by_name()
AUD:
ffmpeg.c::guess_input_channel_layout()
av_get_default_channel_layout()
av_get_channel_layout_string()
DATA, SUB:
avcodec_find_decoder()
ATTACHMENT, UNKNOWN:
// Do Nothing here
avcodec_parameters_from_context()
av_dump_format()
ffmpeg_opt.c::init_complex_filters()
ffmpeg_filter.c::init_complex_filtergraph()
avfilter_graph_alloc()
avfilter_graph_parse2()
on fail,
avfilter_inout_free();
avfilter_graph_free();
For all Inputs,
ffmpeg_filter.c::init_input_filter()
avfilter_pad_get_type()
cmdutils.c::check_stream_specifier()
avformat_match_stream_specifier()
av_fifo_alloc()
For all outputs,
av_mallocz()
avfilter_pad_get_type()
ffmpeg_filter.c::describe_filter_link()
avio_open_dyn_buf()
avio_printf()
avio_w8()
avio_close_dyn_buf()
cmdutils.c::open_files()
ffmpeg_opt.c::open_output_file()
// if no Stream maps
avformat_alloc_output_context2()
av_dict_get()
av_opt_find()
av_opt_eval_flags()
/* create streams for all unlabeled output pads */
ffmpeg_opt.c::init_output_filter()
// Based on Type
VID:
ffmpeg_opt.c::new_video_stream()
ffmpeg_opt.c::new_output_stream()
avformat_new_stream()
av_mallocz()
ffmpeg_opt.c::choose_encoder()
av_guess_codec()
avcodec_find_encoder()
avcodec_alloc_context3()
avcodec_parameters_alloc()
ffmpeg_opt.c::get_preset_file_2()
av_dict_set()
av_free()
avio_closep();
av_parse_ratio() // for Timebase and enc_Timebase
// Parse and Set options
av_parse_video_rate()
av_parse_ratio() // for AspectRatio
av_parse_video_size()
av_get_pix_fmt()
av_fopen_utf8() // log file
ffmpeg_opt.c::get_ost_filters()
read_file() //read filter script from file
avio_open()
avio_open_dyn_buf()
avio_read()
avio_write()
avio_w8()
avio_closep()
avio_close_dyn_buf()
or get from CmdLine av_strdup()
AUD:
ffmpeg_opt.c::new_audio_stream()
ffmpeg_opt.c::new_output_stream() // Same calls as above incase of VID
av_get_sample_fmt()
get_ost_filters()
av_reallocp_array()
avfilter_inout_free()
// Based on Type (VID, AUD)
VID:
av_guess_codec()
avformat_query_codec()
ffmpeg_opt.c::new_video_stream() // Same calls as above
AUD:
av_guess_codec()
ffmpeg_opt.c::new_audio_stream() // Same calls as above
SUBTITLE:
avcodec_find_encoder()
avcodec_descriptor_get()
ffmpeg_opt.c::new_subtitle_stream()
ffmpeg_opt.c::new_output_stream() // Same Calls as above
DATA:
av_guess_codec()
else
// For all stream maps
if LinkLabel
init_output_filter() // Same class as above
else
case AVMEDIA_TYPE_VIDEO: new_video_stream()
case AVMEDIA_TYPE_AUDIO: new_audio_stream()
case AVMEDIA_TYPE_SUBTITLE: new_subtitle_stream()
case AVMEDIA_TYPE_DATA: new_data_stream()
case AVMEDIA_TYPE_ATTACHMENT: new_attachment_stream()
case AVMEDIA_TYPE_UNKNOWN: new_unknown_stream()
/* handle attached files */
avio_open2()
av_malloc()
avio_read()
ffmpeg_opt.c::new_attachment_stream()
av_dict_set()
avio_closep()
// Set options/* set the decoding_needed flags and create simple filtergraphs */
ffmpeg_opt.c::init_simple_filtergraph()
// set the filter output constraints// copy metadata
// copy chapters
// copy global metadata by default// process manually set programs
av_new_program()
on fail, uninit_parse_context()/* The following code is the main loop of the file converter */
ffmpeg.c::transcode()
ffmpeg.c::transcode_init()
//Link FilterGraphs and OutputFilter/* init framerate emulation */
InputFile.InputStreams = av_gettime_relative()/* init input streams */
ffmpeg.c::init_input_stream()
/* Set Dec_Context Options */
av_opt_set_int()
av_dict_set()
ffmpeg_hw.c::hw_device_setup_for_decode()
ffmpeg_hw.c::hw_device_get_by_name()
ffmpeg_hw.c::hw_device_init_from_type()
ffmpeg_hw.c::hw_device_default_name()
av_hwdevice_get_type_name()
av_hwdevice_ctx_create()
ffmpeg_hw.c::hw_device_add()
av_reallocp_array(hw_devices)
av_mallocz()
On fail, av_freep() & av_buffer_unref()
if Generic HWACCEL_AUTO Device,
hw_device_match_by_codec()
avcodec_get_hw_config()
hw_device_init_from_type()
avcodec_open2()
On fail init_input_stream(), Close all Encoding contexts with avcodec_close()
/*
* initialize stream copy and subtitle/data streams.
* Encoded AVFrame based streams will get initialized as follows:
* - when the first AVFrame is received in do_video_out
* - just before the first AVFrame is received in either transcode_step
* or reap_filters due to us requiring the filter chain buffer sink
* to be configured with the correct audio frame size, which is only
* known after the encoder is initialized.
*/
ffmpeg.c::init_output_stream_wrapper()
ffmpeg.c::init_output_stream()
/* If encoding_needed */
ffmpeg.c::init_output_stream_encode()
// Set Options
Based on Codec Type,
AUD:
av_buffersink_get_format()
av_get_bytes_per_sample()
av_buffersink_get_sample_rate()
av_buffersink_get_channel_layout()
av_buffersink_get_channels()ffmpeg.c::init_encoder_time_base() // Based on SampleRate
VID:
ffmpeg.c::init_encoder_time_base() // Based on frameRate
av_buffersink_get_time_base()
av_buffersink_get_w()
av_buffersink_get_h()
av_buffersink_get_sample_aspect_ratio()av_buffersink_get_format()
av_pix_fmt_desc_get()// Set other options on Enc_Context
SUB: // Set options
DATA: // Set Options
ffmpeg_hw.c::hw_device_setup_for_encode()
av_buffersink_get_hw_frames_ctx()
avcodec_get_hw_config()
// Set Enc_Context Options
avcodec_descriptor_get(deCodecContext)
avcodec_descriptor_get(OutputStream)avcodec_open2()
av_buffersink_set_frame_size()
avcodec_parameters_from_context(ost->st->codecpar, ost->enc_ctx)
avcodec_copy_context(ost->st->codec, ost->enc_ctx)
/* if has coded_side_data, */
av_stream_new_side_data()
av_display_rotation_set()
/* else if StreamCopy */
ffmpeg.c::init_output_stream_streamcopy()
avcodec_parameters_to_context()
avcodec_parameters_from_context()
avcodec_parameters_copy()avformat_transfer_internal_stream_timing_info()
// copy timebase while removing common factors
// copy estimated duration as a hint to the muxer
// copy dispositionav_stream_new_side_data()
// Set options on OutputStream// parse user provided disposition, and update stream values
/* initialize bitstream filters for the output stream
* needs to be done here, because the codec id for streamcopy is not
* known until now */
ffmpeg.c::init_output_bsfs()
avcodec_parameters_copy()
av_bsf_init()/* open the muxer when all the streams are initialized */
ffmpeg.c::check_init_output_file()
OuputFile->interrupt_callback = int_cb;
avformat_write_header()/* flush the muxing queues */
/* try to improve muxing time_base (only possible if nothing has been written yet) */
av_fifo_size()
av_fifo_generic_read()
ffmpeg.c::write_packet()
/*
* Audio encoders may split the packets -- #frames in != #packets out.
* But there is no reordering, so we can limit the number of output packets
* by simply dropping them here.
* Counting encoded video frames needs to be done separately because of
* reordering, see do_video_out().
* Do not count the packet when unqueued because it has been counted when queued.
*/
if headers not written
/* the muxer is not initialized yet, buffer the packet */
av_fifo_space()
av_fifo_realloc2()
av_packet_make_refcounted()
av_packet_move_ref()
av_fifo_generic_write()VID:
av_packet_get_side_data()
av_packet_rescale_ts()// set pts, dts
av_interleaved_write_frame()
av_packet_unref()
// discard unused programs/* write headers for files with no streams */
check_init_output_file() // Same calls as above// dump the stream mapping
/// end transcode_init()
/* Return 1 if there remain streams where more output is wanted, 0 otherwise. */
ffmpeg.c::need_output()
close_output_stream()
av_rescale_q()/**
* Run a single step of transcoding.
*
* @return 0 for success, <0 for error
*/
ffmpeg.c::transcode_step()
/**
* Select the output stream to process.
*
* @return selected output stream, or NULL if none available
*/
ffmpeg.c::choose_output()
av_rescale_q()if ffmpeg.c::got_eagain()
ffmpeg.c::reset_eagain()
// return 0 // Stop FFMPEGffmpeg.c::ifilter_has_all_input_formats()
ffmpeg_filter.c::configure_filtergraph()
ffmpeg_filter.c::cleanup_filtergraph()
// Null Output and Input filters
avfilter_graph_free()ffmpeg_hw.c::hw_device_setup_for_filter()
av_buffer_ref()avfilter_inout_free()
avfilter_graph_set_auto_convert()
avfilter_graph_config()/* limit the lists of allowed formats to the ones selected, to
* make sure they stay the same if the filtergraph is reconfigured later */
av_buffersink_get_format()
av_buffersink_get_w()
av_buffersink_get_h()
av_buffersink_get_sample_rate()
av_buffersink_get_channel_layout()AUD: and AV_CODEC_CAP_VARIABLE_FRAME_SIZE = 0
av_buffersink_set_frame_size()Read all input frame queue, av_fifo_size()
av_fifo_generic_read()
av_buffersrc_add_frame()
av_frame_free/* send the EOFs for the finished inputs */
av_buffersrc_add_frame()/* process queued up subtitle packets */
av_fifo_generic_read()
sub2video_update()
avsubtitle_free()
On any fail,
cleanup_filtergraph() // Calls same as above/*
* Similar case to the early audio initialization in reap_filters.
* Audio is special in ffmpeg.c currently as we depend on lavfi's
* audio frame buffering/creation to get the output audio frame size
* in samples correct. The audio frame size for the filter chain is
* configured during the output stream initialization.
*
* Apparently avfilter_graph_request_oldest (called in
* transcode_from_filter just down the line) peeks. Peeking already
* puts one frame "ready to be given out", which means that any
* update in filter buffer sink configuration afterwards will not
* help us. And yes, even if it would be utilized,
* av_buffersink_get_samples is affected, as it internally utilizes
* the same early exit for peeked frames.
*
* In other words, if avfilter_graph_request_oldest would not make
* further filter chain configuration or usage of
* av_buffersink_get_samples useless (by just causing the return
* of the peeked AVFrame as-is), we could get rid of this additional
* early encoder initialization.
*/
ffmpeg.c::init_output_stream_wrapper() // Same calls as above/**
* Perform a step of transcoding for the specified filter graph.
*
* @param[in] graph filter graph to consider
* @param[out] best_ist input stream where a frame would allow to continue
* @return 0 for success, <0 for error
*/
ffmpeg.c::transcode_from_filter()
avfilter_graph_request_oldest()
/**
* Get and encode new output from any of the filtergraphs, without causing
* activity.
*
* @return 0 for success, <0 for severe errors
*/
ffmpeg.c::reap_filters()
AUD:
ffmpeg.c::init_output_stream_wrapper() // Same Calls as beforeav_buffersink_get_frame_flags()
VID:
ffmpeg.c::do_video_out()
ffmpeg.c::init_output_stream_wrapper() // Same Calls as before
ffmpeg.c::adjust_frame_pts_to_encoder_tb()
av_rescale_q(pts,etc...)av_buffersink_get_frame_rate()
// Keyframe settings, pts, dts, SYNC Settings, Calculations
avcodec_send_frame()
av_frame_remove_side_data()avcodec_receive_packet()
av_packet_rescale_ts()/*
* Send a single packet to the output, applying any bitstream filters
* associated with the output stream. This may result in any number
* of packets actually being written, depending on what bitstream
* filters are applied. The supplied packet is consumed and will be
* blank (as if newly-allocated) when this function returns.
*
* If eof is set, instead indicate EOF to all bitstream filters and
* therefore flush any delayed packets to the output. A blank packet
* must be supplied in this case.
*/
ffmpeg.c::output_packet()
/* apply the output bitstream filters */
av_bsf_send_packet()
av_bsf_receive_packet()
write_packet() // Same Calls as aboveav_frame_unref()
AUD:
ffmpeg.c::do_audio_out()
av_init_packet()ffmpeg.c::adjust_frame_pts_to_encoder_tb() // Same calls as above
ffmpeg.c::check_recording_time()
close_output_stream() // Same calls as above// Update pts, opts, frames, etc, etc..
avcodec_receive_packet()
av_packet_rescale_ts()output_packet() // Same calls as above
av_frame_unref()
/*
* Return
* - 0 -- one packet was read and processed
* - AVERROR(EAGAIN) -- no packets were available for selected file,
* this function should be called again
* - AVERROR_EOF -- this function should not be called again
*/
ffmpeg.c::process_input()
ffmpeg.c::get_input_packet()
av_read_frame()/* pkt = NULL means EOF (needed to flush decoder buffers) */
ffmpeg.c::process_input_packet()av_init_packet()
av_rescale_q(dts, ...)AUD:
ffmpeg.c::decode_audio()
/* This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
* There is the following difference: if you got a frame, you must call
* it again with pkt=NULL. pkt==NULL is treated differently from pkt->size==0
*(pkt==NULL means get more output, pkt->size==0 is a flush/drain packet)
*/
ffmpeg.c::decode()
avcodec_send_packet()
avcodec_receive_frame()
ffmpeg.c::check_decode_result()
exit_program(1)// Update timeBases, pts, dts, sample rates etc...
ffmpeg.c::send_frame_to_filters()
av_frame_ref()
ffmpeg.c::ifilter_send_frame()
ffmpeg_filter.c::ifilter_parameters_from_frame()/* (re)init the graph if possible, otherwise buffer the frame and return */
av_frame_clone()
av_fifo_realloc2()
av_fifo_generic_write()ffmpeg.c::reap_filters() // calls same as above
ffmpeg_filters.c::configure_filtergraph() // CSAA
av_buffersrc_add_frame_flags(AV_BUFFERSRC_FLAG_PUSH)
av_frame_unref()
VID:
ffmpeg.c::decode_video()
av_frame_alloc()
av_rescale_q(Timebase)av_realloc_array()
ffmpeg.c::decode() // CSAA
ffmpeg.c::check_decode_result() // CSAAffmpeg_hw.c::hwaccel_retrieve_data()
av_frame_alloc()
av_hwframe_transfer_data()
av_frame_copy_props()av_frame_unref()
av_frame_move_ref()
av_frame_free()on Fail,
av_frame_free()// Set pts, dts, timestams, etc..
av_rescale_q(pts)ffmpeg.c::send_frame_to_filters() // CSAA
On fail,
av_frame_unref()
// Set framerates, next dts, etc etc...
SUBTITLES:
ffmpeg.c::transcode_subtitles()
avcodec_decode_subtitle2()
ffmpeg.c::check_decode_result()on Fail,
ffmpeg.c::sub2video_flush()
ffmpeg.c::sub2video_update()
ffmpeg.c::sub2video_copy_rect()
ffmpeg.c::sub2video_push_ref()
av_buffersrc_add_frame(NULL)av_rescale(pts)
ffmpeg.c::sub2video_update()
av_fifo_alloc()
av_fifo_realloc2()
av_fifo_generic_write()ffmpeg.c::do_subtitle_out()
av_malloc()
av_rescale_q(pts)
avcodec_encode_subtitle()
av_init_packet()
ffmpeg.c::output_packet() // CSAA/* after flushing, send an EOF on all the filter inputs attached to the stream */
/* except when looping we need to flush but not to send an EOF */
ffmpeg.c::send_filter_eof()
ffmpeg.c::ifilter_send_eof()
av_buffersrc_close()
ffmpeg.c::ifilter_parameters_from_codecpar()/* handle stream copy */
// Set pts, dts, etc..
ffmpeg.c::do_streamcopy()
av_init_packet()
output_packet(NULL) // flushif past recoding time, cli,
ffmpeg.c::close_output_stream() // CSAA// force the input stream PTS and other ptd, dts, settings
AUD:
av_get_audio_frame_duration()
av_rescale_delta()ffmpeg.c::output_packet() // CSAA
ffmpeg.c::seek_to_start()
avformat_seek_file()
av_rescale_q()
// Set samples, framerates, duration, etc...ffmpeg.c::get_input_packet() // CSAA
ffmpeg.c::process_input_packet() // CSAA/* mark all outputs that don't go through lavfi as finished */
ffmpeg.c::finish_output_stream()
ffmpeg.c::reset_eagain()// WRAP_CORRECTION Correcting starttime based on the enabled streams
// Settings related to pts, dts, startime, etc, etc../* add the stream-global side data to the first packet */
av_packet_get_side_data()
av_packet_new_side_data()
memcpy()// Dispositon correction.. etc...Settings related to pts, dts, startime, etc, etc..
ffmpeg.c::sub2video_heartbeat()
/* When a frame is read from a file, examine all sub2video streams in
the same file and send the sub2video frame again. Otherwise, decoded
video frames could be accumulating in the filter graph while a filter
(possibly overlay) is desperately waiting for a subtitle frame. */
av_rescale_q()
ffmpeg.c::sub2video_update() // CSAA
av_buffersrc_get_nb_failed_requests()
ffmpeg.c::sub2video_push_ref() // CSAAffmpeg.c::process_input_packet() // CSAA
if discard packet, av_packet_unref()
// End of trasncode_step()/* at the end of stream, we must flush the decoder buffers */
ffmpeg.c::process_input_packet(NULL) // CSAAffmpeg.c::flush_encoders()
ffmpeg.c::finish_output_stream() // CSAA
ffmpeg.c::init_output_stream_wrapper(NULL) // CSAAav_init_packet(NULL)
avcodec_receive_packet()
avcodec_send_frame(NULL)output_packet(NULL)
av_packet_unref()ffmpeg_hw.c::hw_device_free_all()
av_freep()
av_buffer_unref()// Free all output streams, dicts
/// End of transcode()
/// End of main()