The previous article recorded a memory Player Based on FFMPEG, which can be used to read and play data in the memory. This article records a memory Transcoder Based on FFMPEG. The Transcoder can use FFMPEG to read data in the memory. After transcoding to H.264, the data is output to the memory.
For details about how to read data from the memory and output data to the memory, refer:
FFmpeg reads data from memory (or outputs data to memory)
There are two key points for FFMPEG read/write memory:
1. initialize the custom aviocontext and specify the custom callback function.
2. Write the callback function by yourself. Pay attention to the parameters and return values of the function (especially the return values ).
Transcoding is actually a combination of decoding and encoding. For more information, see:
Decoding: 100 lines of code is the simplest Video Player (sdl1.x) based on FFMPEG + SDL)
Encoding: the simplest Video Encoder Based on FFMPEG (YUV encoding: H.264)
Transcoding: the simplest FFMPEG-based transcoding Program
Shows the flowchart of the process program. We can see that avformatcontext of input and output is initialized respectively. Then, decode the input avpacket to obtain the avframe that stores the pixel data (yuv420p format), encode the avframe as the avpacket of H.264, and output the encoded avpacket.
Directly paste the code below:
/*** The simplest example of memory read/write based on FFMPEG (memory Transcoder) ** simplest FFMPEG mem Transcoder, zhang Hui * [email protected] * China Media University/Digital TV technology * Communication University of China/Digital TV technology * http://blog.csdn.net/leixiaohua1020 ** this program implements any format of video data (such as MPEG2) transcode to H. 264 bitstream data. * This program does not process files, but video data in the memory. * It reads data from the memory and outputs The transcoded data to the memory. * Is the simplest example of using FFMPEG to read and write memory. ** This software convert video bitstream (such as MPEG2) to H. 264 * bitstream. it read video bitstream from memory (not from a file), * convert it to H. 264 bitstream, and finally output to another memory. * it's the simplest example to use FFMPEG to read (or write) from * memory. **/# include <stdio. h> extern "C" {# include "libavcodec/avcodec. H "# include" libavformat/avformat. H "# include" libavutil/ Vutil. H "# include" libavutil/OPT. H "# include" libavutil/pixdesc. H "}; file * fp_open; file * fp_write; // read fileint read_buffer (void * opaque, uint8_t * Buf, int buf_size) {If (! Feof (fp_open) {int true_size = fread (BUF, 1, buf_size, fp_open); Return true_size;} else {return-1 ;}} // write fileint write_buffer (void * opaque, uint8_t * Buf, int buf_size) {If (! Feof (fp_write) {int true_size = fwrite (BUF, 1, buf_size, fp_write); Return true_size;} else {return-1 ;}} int flush_encoder (avformatcontext * fmt_ctx, unsigned int stream_index) {int ret; int got_frame; avpacket enc_pkt; If (! (Fmt_ctx-> streams [stream_index]-> codec-> capabilities & codec_cap_delay) return 0; while (1) {av_log (null, av_log_info, "flushing stream # % u encoder \ n", stream_index); // ret = encode_write_frame (null, stream_index, & got_frame); enc_pkt.data = NULL; enc_pkt.size = 0; av_init_packet (& enc_pkt); ret = avcodec_encode_video2 (fmt_ctx-> streams [stream_index]-> codec, & enc_pkt, null, & got_frame); av_frame _ Free (null); If (Ret <0) break; If (! Got_frame) {ret = 0; break;}/* prepare packet for muxing */enc_pkt.stream_index = stream_index; enc_pkt.dts = av_rescale_q_rnd (enc_pkt.dts, fmt_ctx-> streams [stream_index]-> codec-> time_base, fmt_ctx-> streams [stream_index]-> time_base, (avrounding) (Bytes | av_round_pass_minmax )); enc_pkt.pts = av_rescale_q_rnd (enc_pkt.pts, fmt_ctx-> streams [stream_index]-> codec-> time_base, fmt_ctx-> streams [stream_index] -> Time_base, (avrounding) (latency | latency); enc_pkt.duration = av_rescale_q (enc_pkt.duration, fmt_ctx-> streams [stream_index]-> codec-> time_base, fmt_ctx-> streams [stream_index]-> time_base); av_log (null, av_log_debug, "muxing frame \ n");/* MUX encoded frame */ret = av_write_frame (fmt_ctx, & enc_pkt); If (Ret <0) break;} return ret;} int main (INT argc, char * argv []) {int ret; avformatco Ntext * ifmt_ctx = NULL; avformatcontext * ofmt_ctx = NULL; avpacket packet, enc_pkt; avframe * frame = NULL; Enum avmediatype type; unsigned int stream_index; unsigned int I = 0; int got_frame, enc_got_frame; avstream * out_stream; avstream * in_stream; avcodeccontext * dec_ctx, * enc_ctx; avcodec * encoder; fp_open = fopen ("cuc60anniversary_start.ts", "rb "); // video source file fp_write = fopen ("cuc60anniversary_start.h264", "WB +"); // output file Av_register_all (); ifmt_ctx = avformat_alloc_context (); struct (& ofmt_ctx, null, "h264", null); unsigned char * inbuffer = NULL; unsigned char * outbuffer = NULL; inbuffer = (unsigned char *) av_malloc (32768); outbuffer = (unsigned char *) av_malloc (32768);/* Open input file */aviocontext * avio_in = avio_alloc_context (inbuffer, 32768,0, null, read_buffer, null, null); If (avio_in = NULL) goto end; ifmt_ctx -> Pb = avio_in; ifmt_ctx-> flags = avfmt_flag_custom_io; If (ret = avformat_open_input (& ifmt_ctx, "whatever", null, null) <0) {av_log (null, av_log_error, "cannot open input file \ n"); return ret;} If (ret = avformat_find_stream_info (ifmt_ctx, null) <0) {av_log (null, av_log_error, "Cannot find stream information \ n"); return ret;} for (I = 0; I <ifmt_ctx-> nb_streams; I ++) {avstream * stream; avcodeccontex T * codec_ctx; stream = ifmt_ctx-> streams [I]; codec_ctx = stream-> codec;/* reencode video & audio and remux Subtitles etc. */If (codec_ctx-> codec_type = avmedia_type_video) {/* open decoder */ret = avcodec_open2 (codec_ctx, avcodec_find_decoder (codec_ctx-> codec_id), null ); if (Ret <0) {av_log (null, av_log_error, "failed to open decoder for stream # % u \ n", I); return ret ;}}} // av_dump_format (ifmt_ctx, 0 ," Whatever ", 0);/* Open output file */aviocontext * avio_out = avio_alloc_context (outbuffer, 32768,0, null, null, write_buffer, null); If (avio_out = NULL) goto end; // avio_out-> write_packet = write_packet; ofmt_ctx-> Pb = avio_out; ofmt_ctx-> flags = avfmt_flag_custom_io; for (I = 0; I <1; I ++) {out_stream = avformat_new_stream (ofmt_ctx, null); If (! Out_stream) {av_log (null, av_log_error, "failed allocating output stream \ n"); Return averror_unknown;} in_stream = ifmt_ctx-> streams [I]; dec_ctx = in_stream-> codec; enc_ctx = out_stream-> codec; If (dec_ctx-> codec_type = avmedia_type_video) {encoder = avcodec_find_encoder (av_codec_id_h264); enc_ctx-> Height = dec_ctx-height>; enc_ctx-> width = dec_ctx-> width; enc_ctx-> sample_aspect_ratio = dec_ctx-> sample_asp Ect_ratio; enc_ctx-> pix_fmt = encoder-> pix_fmts [0]; enc_ctx-> time_base = dec_ctx-> time_base; // enc_ctx-> time_base.num = 1; // enc_ctx-> time_base.den = 25; // a required option for h264. If not, the error enc_ctx-> me_range = 16; enc_ctx-> max_qdiff = 4 is returned; enc_ctx-> qmin = 10; enc_ctx-> Qmax = 51; enc_ctx-> qcompress = 0.6; enc_ctx-> refs = 3; enc_ctx-> bit_rate = 500000; ret = avcodec_open2 (enc_ctx, encoder, null); If (Ret <0) {av_log (null, av_log_error, "Cannot open Video Encoder for stream # % u \ n", I); return ret ;}} else if (dec_ctx-> codec_type = avmedia_type_unknown) {av_log (null, av_log_fatal, "Elementary stream # % d is of unknown type, cannot proceed \ n", I); return averror_invaliddata ;} else {/* If this stream must be remuxed */ret = avcodec_copy_context (ofmt_ctx-> streams [I]-> codec, ifmt_ctx-> streams [I]-> codec ); if (Ret <0) {av_log (null, av_log _ Error, "copying stream context failed \ n"); return ret ;}}if (ofmt_ctx-> oformat-> flags & avfmt_globalheader) enc_ctx-> flags | = codec_flag_global_header ;} // av_dump_format (ofmt_ctx, 0, "whatever", 1);/* init muxer, write output file header */ret = avformat_write_header (ofmt_ctx, null ); if (Ret <0) {av_log (null, av_log_error, "error occurred when opening output file \ n"); return ret;} I = 0;/* read all packet S */while (1) {I ++; If (ret = av_read_frame (ifmt_ctx, & Packet) <0) break; stream_index = packet. stream_index; If (stream_index! = 0) continue; type = ifmt_ctx-> streams [packet. stream_index]-> codec-> codec_type; av_log (null, av_log_debug, "demuxer gave frame of stream_index % u \ n", stream_index); av_log (null, av_log_debug, "Going to reencode the frame \ n"); frame = av_frame_alloc (); If (! Frame) {ret = averror (enomem); break;} packet. DTS = av_rescale_q_rnd (packet. DTS, ifmt_ctx-> streams [stream_index]-> time_base, ifmt_ctx-> streams [stream_index]-> codec-> time_base, (avrounding) (Bytes | av_round_pass_minmax); packet. PTS = av_rescale_q_rnd (packet. PTS, ifmt_ctx-> streams [stream_index]-> time_base, ifmt_ctx-> streams [stream_index]-> codec-> time_base, (avrounding) (av_round_near_inf | av_round_pa Ss_minmax); ret = avcodec_decode_video2 (ifmt_ctx-> streams [stream_index]-> codec, frame, & got_frame, & Packet); printf ("decode 1 packet \ tsize: % d \ tpts: % d \ n ", packet. size, packet. PTS); If (Ret <0) {av_frame_free (& frame); av_log (null, av_log_error, "decoding failed \ n"); break;} If (got_frame) {frame-> PTS = av_frame_get_best_effort_timestamp (FRAME); frame-> pict_type = av_picture_type_none; enc_pkt.data = NULL; enc_p KT. size = 0; av_init_packet (& enc_pkt); ret = avcodec_encode_video2 (ofmt_ctx-> streams [stream_index]-> codec, & enc_pkt, frame, & enc_got_frame ); printf ("encode 1 packet \ tsize: % d \ tpts: % d \ n", enc_pkt.size, enc_pkt.pts); av_frame_free (& frame); If (Ret <0) goto end; if (! Enc_got_frame) continue;/* prepare packet for muxing */bytes = stream_index; enc_pkt.dts = bytes (enc_pkt.dts, ofmt_ctx-> streams [stream_index]-> codec-> time_base, ofmt_ctx-> streams [stream_index]-> time_base, (avrounding) (av_round_near_inf | av_round_pass_minmax); enc_pkt.pts = av_rescale_q_rnd (enc_pkt.pts, ofmt_ctx-> streams [stream_index]-> codec-> time_base, ofmt_ctx-> streams [stream_ind Ex]-> time_base, (avrounding) (events | events); enc_pkt.duration = av_rescale_q (enc_pkt.duration, ofmt_ctx-> streams [stream_index]-> codec-> time_base, ofmt_ctx-> streams [stream_index]-> time_base); av_log (null, av_log_info, "muxing frame % d \ n", I ); /* MUX encoded frame */av_write_frame (ofmt_ctx, & enc_pkt); If (Ret <0) goto end;} else {av_frame_free (& frame );} av_free_packet (& Packet);}/* fl Ush encoders */for (I = 0; I <1; I ++) {/* flush encoder */ret = flush_encoder (ofmt_ctx, I); If (Ret <0) {av_log (null, av_log_error, "flushing encoder failed \ n"); goto end ;}}predict (ofmt_ctx); End: av_freep (avio_in); av_freep (avio_out ); av_free (inbuffer); av_free (outbuffer); av_free_packet (& Packet); av_frame_free (& frame); convert (& ifmt_ctx); avformat_free_context (ofmt_ctx); fcloseall (); I F (Ret <0) av_log (null, av_log_error, "error occurred \ n"); Return (Ret? 1:0 );}
Result
Shows the program running result.
View the video information before Transcoding Using mediainfo, as shown in.
Use mediainfo to view the transcoded video information, as shown in.
Download
SourceForge project homepage:
Https://sourceforge.net/projects/simplestffmpegmemhandler/
Csdn project:
Http://download.csdn.net/detail/leixiaohua1020/8003731
Note:
This project contains two examples of FFMPEG read/write memory:
Simplest_ffmpeg_mem_player: Memory Player Based on FFMPEG.
Simplest_ffmpeg_mem_transcoder: Memory Transcoder Based on FFMPEG.
The simplest example of memory read/write based on FFMPEG: Memory Transcoder