We plan to record two examples of the simplest FFMPEG for memory read/write. All previous FFMPEG examples operate on files. For example, "100-line code implementation of the simplest Video Player Based on FFMPEG + SDL" plays a video file. The simplest FFMPEG-based transcoding program also converts a video file into another video file. The simplest Video Encoder Based on FFMPEG (YUV encoding is H.264) is also the final encoding to get an H.264 video file. In fact, not all videos are encoded and decoded for files. Sometimes the decoded video data is stored in a memory. For example, video data sent from other systems. Similarly, sometimes the encoded video data does not need to be saved as a file. For example, you must send the encoded video data to another system for further processing. In the above two cases, FFmpeg is required not only to perform the "read, write" Operation on the file, but to perform the "read, write" Operation on the memory. Two examples to be recorded are examples of using FFMPEG to read and write memory.
Examples of FFMPEG read/write memory have been described in the article "FFMPEG reads data from memory (or outputs data to memory)", but there has been no complete code project. This document describes the simplest FFMPEG-based memory player. In this example, the video data in the file is first read to the memory through fread (), and then the data in the memory is played using FFMPEG.
The second example recorded in the next article is "the simplest FFMPEG-based memory Transcoder". In this example, the video data in the file is first read to the memory through fread (), and then the data is read and transcoded using FFMPEG, output The transcoded data to another memory, and write the data into a file through fwrite.
For details about how to read data from memory, refer to the article:
FFmpeg reads data from memory (or outputs data to memory)
Key Points
There are two key points:
1. initialize the custom aviocontext and specify the custom callback function. The sample code is as follows:
// Cache in AVIOContext
unsigned char * aviobuffer = (unsigned char *) av_malloc (32768);
AVIOContext * avio = avio_alloc_context (aviobuffer, 32768,0, NULL, read_buffer, NULL, NULL);
pFormatCtx-> pb = avio;
if (avformat_open_input (& pFormatCtx, NULL, NULL, NULL)! = 0) {
printf ("Could n‘t open inputstream. \ n");
return -1;
}
In the above Code, the callback function read_buffer () is customized (). When you use avformat_open_input () to open media data, you can choose not to specify the File URL, that is, the 2nd parameter is null (because the data is not read by the file, but by read_buffer () provided)
2. Write the callback function by yourself. The sample code is as follows:
//Callback
int read_buffer(void *opaque, uint8_t *buf, int buf_size){
if(!feof(fp_open)){
inttrue_size=fread(buf,1,buf_size,fp_open);
return true_size;
}else{
return -1;
}
}
When the system needs data, the callback function is automatically called to obtain data. In this example, fread () is directly used to read data to the memory for simplicity. The callback function must pay special attention to its parameters and return values.
Source code
The source code of the program is directly pasted below:
/ **
* The simplest example of memory reading and writing based on FFmpeg (memory player)
* Simplest FFmpeg mem Player
*
* Lei Xiaoyu
* [email protected]
* Communication University of China / Digital TV Technology
* Communication University of China / Digital TV Technology
* http://blog.csdn.net/leixiaohua1020
*
* This program implements playback of video data in memory.
* Is the simplest example of using FFmpeg to read memory.
*
* This software play video data in memory (not a file).
* It ’s the simplest example to use FFmpeg to read from memory.
*
* /
#include <stdio.h>
extern "C"
{
#include "libavcodec / avcodec.h"
#include "libavformat / avformat.h"
#include "libswscale / swscale.h"
// SDL
#include "sdl / SDL.h"
#include "sdl / SDL_thread.h"
};
// Output YUV420P
#define OUTPUT_YUV420P 0
FILE * fp_open = NULL;
// Callback
int 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;
}
}
int main (int argc, char * argv [])
{
AVFormatContext * pFormatCtx;
int i, videoindex;
AVCodecContext * pCodecCtx;
AVCodec * pCodec;
char filepath [] = "cuc60anniversary_start.mkv";
Ranch
av_register_all ();
avformat_network_init ();
pFormatCtx = avformat_alloc_context ();
Ranch
fp_open = fopen (filepath, "rb +");
// Cache in AVIOContext
unsigned char * aviobuffer = (unsigned char *) av_malloc (32768);
AVIOContext * avio = avio_alloc_context (aviobuffer, 32768,0, NULL, read_buffer, NULL, NULL);
pFormatCtx-> pb = avio;
if (avformat_open_input (& pFormatCtx, NULL, NULL, NULL)! = 0) {
printf ("Could n‘t open input stream. \ n");
return -1;
}
if (av_find_stream_info (pFormatCtx) <0) {
printf ("Could n‘t find stream information. \ n");
return -1;
}
videoindex = -1;
for (i = 0; i <pFormatCtx-> nb_streams; i ++)
if (pFormatCtx-> streams [i]-> codec-> codec_type == AVMEDIA_TYPE_VIDEO) {
videoindex = i;
break;
}
if (videoindex ==-1) {
printf ("Did n‘t find a video stream. \ n");
return -1;
}
pCodecCtx = pFormatCtx-> streams [videoindex]-> codec;
pCodec = avcodec_find_decoder (pCodecCtx-> codec_id);
if (pCodec == NULL) {
printf ("Codec not found. \ n");
return -1;
}
if (avcodec_open2 (pCodecCtx, pCodec, NULL) <0) {
printf ("Could not open codec. \ n");
return -1;
}
AVFrame * pFrame, * pFrameYUV;
pFrame = avcodec_alloc_frame ();
pFrameYUV = avcodec_alloc_frame ();
uint8_t * out_buffer = (uint8_t *) av_malloc (avpicture_get_size (PIX_FMT_YUV420P, pCodecCtx-> width, pCodecCtx-> height));
avpicture_fill ((AVPicture *) pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx-> width, pCodecCtx-> height);
// SDL ----------------------------
if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf ("Could not initialize SDL-% s \ n", SDL_GetError ());
return -1;
}
int screen_w = 0, screen_h = 0;
SDL_Surface * screen;
screen_w = pCodecCtx-> width;
screen_h = pCodecCtx-> height;
screen = SDL_SetVideoMode (screen_w, screen_h, 0,0);
if (! screen) {
printf ("SDL: could not set video mode-exiting:% s \ n", SDL_GetError ());
return -1;
}
SDL_Overlay * bmp;
bmp = SDL_CreateYUVOverlay (pCodecCtx-> width, pCodecCtx-> height, SDL_YV12_OVERLAY, screen);
SDL_Rect rect;
// SDL End ------------------------
int ret, got_picture;
AVPacket * packet = (AVPacket *) av_malloc (sizeof (AVPacket));
// Output Information -----------------------------
printf ("File Information --------------------------------- \ n");
av_dump_format (pFormatCtx, 0, filepath, 0);
printf ("----------------------------------------------- -\ n ");
#if OUTPUT_YUV420P
FILE * fp_yuv = fopen ("output.yuv", "wb +");
#endif
struct SwsContext * img_convert_ctx;
img_convert_ctx = sws_getContext (pCodecCtx-> width, pCodecCtx-> height, pCodecCtx-> pix_fmt, pCodecCtx-> width, pCodecCtx-> height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL)
// ------------------------------
while (av_read_frame (pFormatCtx, packet)> = 0) {
if (packet-> stream_index == videoindex) {
ret = avcodec_decode_video2 (pCodecCtx, pFrame, & got_picture, packet);
if (ret <0) {
printf ("Decode Error. \ n");
return -1;
}
if (got_picture) {
sws_scale (img_convert_ctx, (const uint8_t * const *) pFrame-> data, pFrame-> linesize, 0, pCodecCtx-> height, pFrameYUV-> data, pFrameYUV-> linesize);
#if OUTPUT_YUV420P
int y_size = pCodecCtx-> width * pCodecCtx-> height;
fwrite (pFrameYUV-> data [0], 1, y_size, fp_yuv); // Y
fwrite (pFrameYUV-> data [1], 1, y_size / 4, fp_yuv); // U
fwrite (pFrameYUV-> data [2], 1, y_size / 4, fp_yuv); // V
#endif
SDL_LockYUVOverlay (bmp);
bmp-> pixels [0] = pFrameYUV-> data [0];
bmp-> pixels [2] = pFrameYUV-> data [1];
bmp-> pixels [1] = pFrameYUV-> data [2];
bmp-> pitches [0] = pFrameYUV-> linesize [0];
bmp-> pitches [2] = pFrameYUV-> linesize [1];
bmp-> pitches [1] = pFrameYUV-> linesize [2];
SDL_UnlockYUVOverlay (bmp);
rect.x = 0;
rect.y = 0;
rect.w = screen_w;
rect.h = screen_h;
SDL_DisplayYUVOverlay (bmp, & rect);
// Delay 40ms
SDL_Delay (40);
}
}
av_free_packet (packet);
}
sws_freeContext (img_convert_ctx);
#if OUTPUT_YUV420P
fclose (fp_yuv);
#endif
fclose (fp_open);
SDL_Quit ();
av_free (out_buffer);
av_free (pFrameY
UV);
avcodec_close (pCodecCtx);
avformat_close_input (& pFormatCtx);
return 0;
}
You can determine whether to output the decoded yuv420p data into a file through the macro defined in the Code:
#define OUTPUT_YUV420P 0
Result
The running result of the program is as follows. You can decode and play the test video. The celebration of the 60th anniversary was followed by a short opening scene of the gala as a test video for the alma mater ~
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 (record in the next article ).
The simplest example of memory read/write based on FFMPEG: Memory player