`
xpp02
  • 浏览: 1014115 次
社区版块
存档分类
最新评论

FFPLAY的原理(二)

 
阅读更多

关于包Packets的注释

从技术上讲一个包可以包含部分或者其它的数据,但是ffmpeg的解释器保证了我们得到的包Packets包含的要么是完整的要么是多种完整的帧。

现在我们需要做的是让SaveFrame函数能把RGB信息定稿到一个PPM格式的文件中。我们将生成一个简单的PPM格式文件,请相信,它是可以工作的。

void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {

FILE *pFile;

char szFilename[32];

int y;

// Open file

sprintf(szFilename, "frame%d.ppm", iFrame);

pFile=fopen(szFilename, "wb");

if(pFile==NULL)

return;

// Write header

fprintf(pFile, "P6/n%d %d/n255/n", width, height);

// Write pixel data

for(y=0; y<height; y++)

fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);

// Close file

fclose(pFile);

}

我们做了一些标准的文件打开动作,然后写入RGB数据。我们一次向文件写入一行数据。PPM格式文件的是一种包含一长串的RGB数据的文件。如果你了解 HTML色彩表示的方式,那么它就类似于把每个像素的颜色头对头的展开,就像#ff0000#ff0000....就表示了了个红色的屏幕。(它被保存成二进制方式并且没有分隔符,但是你自己是知道如何分隔的)。文件的头部表示了图像的宽度和高度以及最大的RGB值的大小。

现在,回顾我们的main()函数。一旦我们开始读取完视频流,我们必需清理一切:

// Free the RGB image

av_free(buffer);

av_free(pFrameRGB);

// Free the YUV frame

av_free(pFrame);

// Close the codec

avcodec_close(pCodecCtx);

// Close the video file

av_close_input_file(pFormatCtx);

return 0;

你会注意到我们使用av_free来释放我们使用avcode_alloc_fram和av_malloc来分配的内存。

上面的就是代码!下面,我们将使用Linux或者其它类似的平台,你将运行:

gcc -o tutorial01 tutorial01.c -lavutil -lavformat -lavcodec -lz -lavutil -lm

如果你使用的是老版本的ffmpeg,你可以去掉-lavutil参数:

gcc -o tutorial01 tutorial01.c -lavutil -lavformat -lavcodec -lz -lm

大多数的图像处理函数可以打开PPM文件。可以使用一些电影文件来进行测试。

输出到屏幕

SDL和视频

为了在屏幕上显示,我们将使用SDL.SDL是Simple Direct Layer的缩写。它是一个出色的多媒体库,适用于多平台,并且被用在许多工程中。你可以从它的官方网站的网址 http://www.libsdl.org/ 上来得到这个库的源代码或者如果有可能的话你可以直接下载开发包到你的操作系统中。按照这个指导,你将需要编译这个库。(剩下的几个指导中也是一样)

SDL库中有许多种方式来在屏幕上绘制图形,而且它有一个特殊的方式来在屏幕上显示图像――这种方式叫做YUV覆盖。YUV(从技术上来讲并不叫 YUV而是叫做YCbCr)是一种类似于RGB方式的存储原始图像的格式。粗略的讲,Y是亮度分量,U和V是色度分量。(这种格式比RGB复杂的多,因为很多的颜色信息被丢弃了,而且你可以每2个Y有1个U和1个V)。SDL的YUV覆盖使用一组原始的YUV数据并且在屏幕上显示出他们。它可以允许4种不同的 YUV格式,但是其中的YV12是最快的一种。还有一个叫做YUV420P的YUV格式,它和YV12是一样的,除了U和V分量的位置被调换了以外。 420意味着它以4:2:0的比例进行了二次抽样,基本上就意味着1个颜色分量对应着4个亮度分量。所以它的色度信息只有原来的1/4。这是一种节省带宽的好方式,因为人眼感觉不到这种变化。在名称中的P表示这种格式是平面的――简单的说就是Y,U和V分量分别在不同的数组中。FFMPEG可以把图像格式转换为YUV420P,但是现在很多视频流的格式已经是YUV420P的了或者可以被很容易的转换成YUV420P格式。

于是,我们现在计划把指导1中的SaveFrame()函数替换掉,让它直接输出我们的帧到屏幕上去。但一开始我们必需要先看一下如何使用SDL库。首先我们必需先包含SDL库的头文件并且初始化它。

#include <SDL.h>

#include <SDL_thread.h>

if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {

fprintf(stderr, "Could not initialize SDL - %s/n", SDL_GetError());

exit(1);

}

SDL_Init()函数告诉了SDL库,哪些特性我们将要用到。当然SDL_GetError()是一个用来手工除错的函数。

创建一个显示

现在我们需要在屏幕上的一个地方放上一些东西。在SDL中显示图像的基本区域叫做面surface。

SDL_Surface *screen;

screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);

if(!screen) {

fprintf(stderr, "SDL: could not set video mode - exiting/n");

exit(1);

}

这就创建了一个给定高度和宽度的屏幕。下一个选项是屏幕的颜色深度――0表示使用和当前一样的深度。(这个在OS X系统上不能正常工作,原因请看源代码)

现在我们在屏幕上来创建一个YUV覆盖以便于我们输入视频上去:

SDL_Overlay *bmp;

bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,

SDL_YV12_OVERLAY, screen);

正如前面我们所说的,我们使用YV12来显示图像。

显示图像

前面那些都是很简单的。现在我们需要来显示图像。让我们看一下是如何来处理完成后的帧的。我们将原来对RGB处理的方式,并且替换 SaveFrame() 为显示到屏幕上的代码。为了显示到屏幕上,我们将先建立一个AVPicture结构体并且设置其数据指针和行尺寸来为我们的YUV覆盖服务:

if(frameFinished) {

SDL_LockYUVOverlay(bmp);

AVPicture pict;

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,

(AVPicture *)pFrame, pCodecCtx->pix_fmt,

pCodecCtx->width, pCodecCtx->height);

SDL_UnlockYUVOverlay(bmp);

}

首先,我们锁定这个覆盖,因为我们将要去改写它。这是一个避免以后发生问题的好习惯。正如前面所示的,这个AVPicture结构体有一个数据指针指向一个有4个元素的指针数据。由于我们处理的是YUV420P,所以我们只需要3个通道即只要三组数据。其它的格式可能需要第四个指针来表示alpha通道或者其它参数。行尺寸正如它的名字表示的意义一样。在YUV覆盖中相同功能的结构体是像素pixel和程度pitch。(程度pitch是在SDL里用来表示指定行数据宽度的值)。所以我们现在做的是让我们的覆盖中的pict.data中的三个指针有一个指向必要的空间的地址。类似的,我们可以直接从覆盖中得到行尺寸信息。像前面一样我们使用img_convert来把格式转换成PIX_FMT_YUV420P。

绘制图像

但我们仍然需要告诉SDL如何来实际显示我们给的数据。我们也会传递一个表明电影位置、宽度、高度和缩放大小的矩形参数给SDL的函数。这样,SDL为我们做缩放并且它可以通过显卡的帮忙来进行快速缩放。

SDL_Rect rect;

if(frameFinished) {

// Convert the image into YUV format that SDL uses

img_convert(&pict, PIX_FMT_YUV420P,

(AVPicture *)pFrame, pCodecCtx->pix_fmt,

pCodecCtx->width, pCodecCtx->height);

SDL_UnlockYUVOverlay(bmp);

rect.x = 0;

rect.y = 0;

rect.w = pCodecCtx->width;

rect.h = pCodecCtx->height;

SDL_DisplayYUVOverlay(bmp, &rect);

}

让我们再花一点时间来看一下SDL的特性:它的事件驱动系统。SDL被设置成当你在SDL中点击或者移动鼠标或者向它发送一个信号它都将产生一个事件的驱动方式。如果你的程序想要处理用户输入的话,它就会检测这些事件。你的程序也可以产生事件并且传递给SDL事件系统。当使用SDL进行多线程编程的时候,这相当有用,这方面代码我们可以在指导4中看到。在这个程序中,我们将在处理完包以后就立即轮询事件。现在而言,我们将处理SDL_QUIT事件以便于我们退出:

SDL_Event event;

av_free_packet(&packet);

SDL_PollEvent(&event);

switch(event.type) {

case SDL_QUIT:

SDL_Quit();

exit(0);

break;

default:

break;

}

让我们去掉旧的冗余代码,开始编译。如果你使用的是Linux或者其变体,使用SDL库进行编译的最好方式为:

gcc -o tutorial02 tutorial02.c -lavutil -lavformat -lavcodec -lz -lm /

`sdl-config --cflags --libs`

这里的sdl-config命令会打印出用于gcc编译的包含正确SDL库的适当参数。为了进行编译,在你自己的平台你可能需要做的有点不同:请查阅一下SDL文档中关于你的系统的那部分。一旦可以编译,就马上运行它。

当运行这个程序的时候会发生什么呢?电影简直跑疯了!实际上,我们只是以我们能从文件中解码帧的最快速度显示了所有的电影的帧。现在我们没有任何代码来计算出我们什么时候需要显示电影的帧。最后(在指导5),我们将花足够的时间来探讨同步问题。但一开始我们会先忽略这个,因为我们有更加重要的事情要处理:音频!

分享到:
评论

相关推荐

    ffplay原理讲解

    ffplay原理详细讲解,讲述ffplay的实现过程

    流媒体:FFPLAY原理+FFmpeg框架+SDL资料及代码解析

    流媒体:FFPLAY原理+FFmpeg框架+SDL资料及代码解析

    FFPLAY的原理 源码讲解

    FFPLAY资源详细讲解,带源码注释,求给力,评论可返回分数的

    ffplay for MFC (stable)

    自己做的FFPLAY移植到VC下的开源工程:ffplay for MFC。 本工程将ffmpeg项目中的ffplay播放器(ffplay.c)移植到了VC...通过本程序可以学习视频播放器原理,以及SDL和Windows消息机制等。代码中包含了比较详细的注释。

    ffplay原理

    10 从video.avi文件中打开视频流video_stream 20 从视频流中读取包到帧中 30 如果这个帧还不完整,跳到20 40 对这个帧进行一些操作 50 跳回到20

    ffempeg+sdl+FFPLAY的原理教程以及代码

    使用sdl框架结合ffmepg解码实现ios平台视频播放器FFPLAY的原理以及部分研究代码

    ffmpeg的ffplay源码剖析

    ffmpeg的ffplay源码剖析,包括ffplay每一个程序文件的解释和功能描述。还包括播放器的原理、架构概述、sdl显示音频和视频压缩算法等。

    FFPLAY的原理和FFmpeg框架代码结构和SDL相关资料

    FFPLAY的原理和FFmpeg框架和SDL相关资料 资料不是很多,不过对入门很有帮助 FFmpeg,SDL结合,强大啊 都是入门级的资料 自己当前在学这些东西,整理下,呵呵 大家都交流下咯 密码:2005 分要多点,大家下载后评论就...

    ffplay for MFC 1.0.1

    自己做的FFPLAY移植到VC下的开源工程:ffplay for MFC。 本工程将ffmpeg项目中的ffplay播放器(ffplay.c)移植到了VC...通过本程序可以学习视频播放器原理,以及SDL和Windows消息机制等。代码中包含了比较详细的注释。

    FFMPEG/FFPLAY源码剖析(作者 杨书良)完整清晰pdf

    FFMPEG/FFPLAY源码剖析:方便可以快速的学习ffmpeg架构,迈出学习ffmpeg的第一步

    FFPLAY的源码剖析与开发指南

    详尽的分析了ffplay的源码处理流程,共69页。 让你对视频开发以及编解码有更深入的理解。

    FFmpeg4.3开发系列之五:SDK二次开发详解与直播实战

    2、您将学会“协议层”的原理流程、数据结构、API和项目实战案例。 3、您将学会“封装层”的原理流程、数据结构、API和项目实战案例。 4、您将学会“编码层”的原理流程、数据结构、API和项目实战案例。 5、您将学会...

    FFmpeg 源码剖析.rar

    1.1 ffplay 文件概览 . . . . . . . . . . . . . . . ....1.2 播放器一般原理 ....1.3 ffplay 播放器原理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4 ffpla

    音视频资料,内含各种资料,见描述

    FFMEPG入门、FFMPEG内存模型和播放器框架讲解、音视频同步分析-基于ffplay、Advanced Audio Coding (AAC)、新一代视频压缩码标准-H.264_AVC(第二版)、新一代高效视频编码H.265HEVC原理、标准与实现、FLV标准文档、...

    ffmpeg视频教程全套 音视频直播水印culinary开发进阶C++/C

    文件很大24G ffmpeg音视频处理 直播水印culinary开发进阶C++/C视频教程...课程主要介绍了ffmpeg在windows和liux上的安装,ffmpeg,ffprobe,ffplay命令的基本使用,提取音频,视频,合并音视频,对视频添加水印等常用功能。

    如何用 FFmpeg 编写一个简单播放器详 细步骤介绍--FFmpeg中文版

    有一个单独的指导讲了它的基本原理另 外还有一个使用 doxygen 生成的文档。这就是为什么当我决定研究 FFMPEG 来弄 清楚音视频应用程序是如何工作的过程中,我决定把这个过程用文档的形式记录 并且发布出来作为初学...

    rcloneExplorer:rclone GUI for Windows

    rcloneExplorer的工作原理是从rclone中获取输出,从而完成了所有繁重的工作。 通过rclones配置过程设置的遥控器应在rcloneExplorer中完全可用。 rcloneExplorer只能访问rclone配置的遥控器。 特征 流媒体 利用“ ...

    FFmpeg4.3开发系列之四:命令行实践与解析

    我将带领大家一起来学习ffmpeg的常用命令,包括音视频编解码、流媒体直播,同时讲解原理。大家在学习中遇到的各种问题,需要多总结分析、及时提问。     具体内容包括如下: 三大命令行的选项分析:ffmpeg,ffplay,...

    StreamMediaMemand:一个基于live555系统做了增强,在些基础上加入了更多的视频格式

    加入的去mp4文件的支持原理:mediaServer只支持".m4e"格式的Elementary Stream fie,但并不支持串流mp4封装格式的文件,要串流mp4格式的文件一般都是结合FFmpeg进行,但是代码量稍大,这里使用一种较为简单的方法...

Global site tag (gtag.js) - Google Analytics