FFmpeg入门(4)-An ffmpeg and SDL Tutorial 2
2014-04-23 18:10
375 查看
An ffmpeg and SDL Tutorial 2 中将1中的保存图片改为用SDL显示,在显示之前要讲本地帧改为YUV420P格式。
对照1把2 的代码进行相应修改得到:
程序2编译 运行
gcc -o tutorial02 tutorial02.1.c -lavutil -lavformat -lavcodec -lz -lm `sdl-config --cflags --libs`
gcc -g -o tutorial02 tutorial02.1.c -lavutil -lavformat -lavcodec -lswscale -lz -lm -lpthread `sdl-config --cflags --libs`
http://my.oschina.net/u/589963/blog/167766
YUV格式通常有两大类:打包(packed)格式和平面(planar)格式。前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组分开存放YUV三个分量
YUV420P(planar格式)在ffmpeg中存储是在struct ***Frame的data[]数组中
data[0]-------Y分量 data[1]------U分量
data[2]-------V分量
YUV420P的内存结构:
4个Y分量对应1个UV分量
YUV420格式是指,每个像素都保留一个Y(亮度)分量,而在水平方向上,不是每行都取U和V分量,而是一行只取U分量,则其接着一行就只取V分量,以此重复(即4:2:0,
4:0:2, 4:2:0, 4:0:2 .......),所以420不是指没有V,而是指一行采样只取U,另一行采样只取V。在取U和V时,每两个Y之间取一个U或V。但从4x4矩阵列来看,每4个矩阵点Y区域中,只有一个U和V,所以它们的比值是4:1。所以对于一个像素,RGB需要8 * 3 = 24位,即占3个字节;而YUV420P,8 + 8/4 + 8/4 = 12位,即占2个字节,其中8指Y分量,8/4指U和V分量。
YUV420内存格式:
YYYYYYYY UU VV
------最常见的
YYYYYYYY UU VV
------也有,不过我开发中没遇到过
我们用ffmpeg把yuv420P 存储到文件中,然后利用一些yuv播放器就可以播放YUV原始数据,貌似VLC不能播放YUV原始数据:
data[]中存放着YUV原始数据(在struct ***Frame中的,位于frame.h中----ffmpeg)
对照1把2 的代码进行相应修改得到:
#include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #include <SDL/SDL.h> #include <SDL/SDL_thread.h> #include <unistd.h> //slq static ***FormatContext *pFormatCtx = NULL; int main(int argc, char *argv[]) { // ***FormatContext *pFormatCtx; // static ***FormatContext *pFormatCtx = NULL; ***CodecContext *pCodecCtx; ***Codec *pCodec; ***Frame *pFrame; ***Frame *pFrameRGB; ***Packet packet; SDL_Surface *screen; SDL_Overlay *bmp; uint8_t *buffer; int numBytes; int i; av_register_all(); //slq //reads the file header and stores information about the file format in the ***FormatContext structure pFormatCtx if (avformat_open_input( &pFormatCtx, argv[1], NULL, NULL) < 0) //if (avformat_open_input( &input_fmt_ctx, input_file, NULL, NULL) < 0) { //if (av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL) != 0) return -1; // Retrieve stream information if (av_find_stream_info(pFormatCtx) < 0) return -1; // Dump information about file onto standard error // dump_format(pFormatCtx, 0, argv[1], 0); av_dump_format(pFormatCtx, 0, argv[1], 0); // Find the first video stream int videoStream = -1; for (i = 0; i < pFormatCtx->nb_streams; ++i) { if (pFormatCtx->streams[i]->codec->codec_type == ***MEDIA_TYPE_VIDEO) { videoStream = i; break; } } // Get a pointer to the codec context for the video stream pCodecCtx = pFormatCtx->streams[videoStream]->codec; // Find the decoder for the video stream pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec == NULL) { fprintf(stderr, "Unsupported codec@!\n"); } // Open codec //slq if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) //if (avcodec_open(pCodecCtx, pCodec) < 0) return -1; // Allocate video frame (native format) pFrame = avcodec_alloc_frame(); // Allocate an ***Frame structure ( RGB ) pFrameRGB = avcodec_alloc_frame(); if (pFrameRGB == NULL) return -1; // we still need a place to put the raw data when we convert it. //We use avpicture_get_size to get the size we need, //and allocate the space manually: // Determine required buffer size and allocate buffer numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height); //av_malloc is ffmpeg's malloc that is just a simple wrapper around malloc that makes sure the memory addresses are aligned and such. buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t)); // Assign appropriate parts of buffer to image planes n. 图像平面;映像平面 in pFrameRGB // Note that pFrameRGB is an ***Frame, but ***Frame is a superset // of ***Picture avpicture_fill((***Picture *) pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height); /* * SDL */ //SDL_Init() essentially tells the library what features we're going to use if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); exit(1); } //This sets up a screen with the given width and height. //The next option is the bit depth of the screen - 0 is a special value that means "same as the current display". screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0); if (!screen) { fprintf(stderr, "SDL: could not set video mode - exiting\n"); exit(1); } //using YV12 to display the image bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen); i = 0; while (av_read_frame(pFormatCtx, &packet) >= 0) { // Is this a packet from the video stream? if (packet.stream_index == videoStream) { int frameFinished; /* avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, packet.data, packet.size); */ avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); // Did we get a video frame? if (frameFinished) { #ifdef S***EFILE /*保存到文件*/ /* *此函数已经不用 img_convert((***Picture *)pFrameRGB, PIX_FMT_RGB24, (***Picture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height); */ static struct SwsContext *img_convert_ctx; img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height , pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC , NULL, NULL, NULL); sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); if(++i <= 5) SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i); #else /*显示 */ ***Picture pict; static struct SwsContext *img_convert_ctx; SDL_Rect rect; SDL_LockYUVOverlay(bmp); pict.data[0] = bmp->pixels[0]; pict.data[1] = bmp->pixels[2]; pict.data[2] = bmp->pixels[1]; pict.linesize[0] = bmp->pitches[0]; pict.linesize[1] = bmp->pitches[2]; pict.linesize[2] = bmp->pitches[1]; /* // Convert the image into YUV format that SDL uses img_convert(&pict, PIX_FMT_YUV420P, (***Picture *) pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height); */ img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); sws_scale(img_convert_ctx, (const uint8_t* const *) pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pict.data, pict.linesize); SDL_UnlockYUVOverlay(bmp); rect.x = 0; rect.y = 0; rect.w = pCodecCtx->width; rect.h = pCodecCtx->height; SDL_DisplayYUVOverlay(bmp, &rect); #endif usleep(25000); } } // Free the packet that was allocated by av_read_frame av_free_packet(&packet); } av_free(buffer); av_free(pFrameRGB); av_free(pFrame); avcodec_close(pCodecCtx); av_close_input_file(pFormatCtx); return 0; }
程序2编译 运行
gcc -o tutorial02 tutorial02.1.c -lavutil -lavformat -lavcodec -lz -lm `sdl-config --cflags --libs`
gcc -g -o tutorial02 tutorial02.1.c -lavutil -lavformat -lavcodec -lswscale -lz -lm -lpthread `sdl-config --cflags --libs`
YUV420P格式分析
http://my.oschina.net/u/589963/blog/167766YUV格式通常有两大类:打包(packed)格式和平面(planar)格式。前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组分开存放YUV三个分量
YUV420P(planar格式)在ffmpeg中存储是在struct ***Frame的data[]数组中
data[0]-------Y分量 data[1]------U分量
data[2]-------V分量
YUV420P的内存结构:
4个Y分量对应1个UV分量
YUV420格式是指,每个像素都保留一个Y(亮度)分量,而在水平方向上,不是每行都取U和V分量,而是一行只取U分量,则其接着一行就只取V分量,以此重复(即4:2:0,
4:0:2, 4:2:0, 4:0:2 .......),所以420不是指没有V,而是指一行采样只取U,另一行采样只取V。在取U和V时,每两个Y之间取一个U或V。但从4x4矩阵列来看,每4个矩阵点Y区域中,只有一个U和V,所以它们的比值是4:1。所以对于一个像素,RGB需要8 * 3 = 24位,即占3个字节;而YUV420P,8 + 8/4 + 8/4 = 12位,即占2个字节,其中8指Y分量,8/4指U和V分量。
YUV420内存格式:
YYYYYYYY UU VV
------最常见的
YYYYYYYY UU VV
------也有,不过我开发中没遇到过
我们用ffmpeg把yuv420P 存储到文件中,然后利用一些yuv播放器就可以播放YUV原始数据,貌似VLC不能播放YUV原始数据:
data[]中存放着YUV原始数据(在struct ***Frame中的,位于frame.h中----ffmpeg)
相关文章推荐
- FFmpeg入门(3)-An ffmpeg and SDL Tutorial
- FFmpeg入门(5)-An ffmpeg and SDL Tutorial 3
- An ffmpeg and SDL Tutorial 02
- An ffmpeg and SDL Tutorial or How to Write a Video Player in Less Than 1000 Lines
- An ffmpeg and SDL Tutorial
- ffmpeg学习(2)--An ffmpeg and SDL Tutorial
- An ffmpeg and SDL Tutorial 学习笔记(一)
- An ffmpeg and SDL Tutorial 学习笔记(四)
- An ffmpeg and SDL Tutorial 00
- An ffmpeg and SDL Tutorial在ffmpeg-1.0.1上的更新,tutorial02
- An ffmpeg and SDL Tutorial 学习笔记(六)
- An ffmpeg and SDL Tutorial 03
- An ffmpeg and SDL Tutorial
- An ffmpeg and SDL Tutorial
- An ffmpeg and SDL Tutorial 学习笔记(三)
- An ffmpeg and SDL Tutorial 04
- An ffmpeg and SDL Tutorial
- An ffmpeg and SDL Tutorial or How to Write a Video Player in Less Than 1000 Lines
- An ffmpeg and SDL Tutorial 05
- An ffmpeg and SDL Tutorial 学习笔记(五)