文档章节

ffmpeg解码视频并输出到屏幕

曾经花田错
 曾经花田错
发布于 2016/12/07 14:49
字数 1019
阅读 125
收藏 0
点赞 0
评论 0

* 学习自雷神的博客和视频,图片来自他的课件,雷神博客:* 

http://blog.csdn.NET/leixiaohua1020/

 

ffmpeg基础知识

ffmpeg的库

  • avdecoc: 编解码
  • avformat: 封装格式的处理(mkv,mp4,avi)
  • swscale: 视频像素数据格式转换(常用于解码后视频的裁剪)
  • avutil: 工具库
  • avfilter: 滤镜特效处理
  • avdevice: 各种设备的输入输出
  • postproc: 后加工
  • swresample: 音频采样数据格式转换

ffmpeg的执行流程

        

  • avcodec_decode_open2()这个函数是解码函数, 最主要的一个函数。
  •   图中解码流程是:获取一个pakcet, 然后调用解码函数,把AVPacket结构中的data转换为AVFrame结构的data。
  • AVPacket结构存储一帧压缩的编码数据。
  • AVFrame结构存储一帧解码后的像素数据(对音频则是采样数据)。
  • AVFrame结构的元素data是双重指针,YUV数据来说包含data[0],data[1],data[2]分别存Y、U、V数据,注意每帧中U、V数据是Y数据的四分之一大小(对420P来说)。『Y:亮度数据, U,V:色差数据,由于人的眼睛对亮度更敏感,故而YUV数据中存更多的Y而减少UV的数据。当只有Y数据的时候,显示为黑白』 
  • 解码出来的数据可能函数无效像素。需要用sws_scale()函数处理。
  • 如图: 

         

 

ffmpeg 解码相关结构体

        

  • AVFormatContext是一个统筹全局的结构, 包含一些视频文件名,视频时长,视频码率等封装格式信息。 
  • AVInputFormat包含一些具体的视频格式信息,每种视频格式对应一个这个结构。
  •  一般来说视频文件有两个流:视频流和音频流。有几个流就有几个AVStream数据结构, 一般视频流的index==0(也有其他情况), AVStream在AVFormatContext中是一个双重指针。 
  • AVCodecContext 编解码器上下文结构体,保存音视频编解码相关信息。
  • AVCodec 每种视/音频编解码器(例如h264)对应一个该结构体。

SDL显示YUV图像流程:

        

  •  SDL_Surface就是使用SDL的时候弹出的那个窗口。
  • SDL_Overlay用于显示YUV数据。一个SDL_Overlay对应一帧YUV数据。
  • SDL_Rect用于确定SDL_Overlay显示的位置。

代码 

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_thread.h>

int main(int argc, char *argv[]) {
    AVFormatContext *pFormatCtx = NULL;
    int             i, videoStream;
    AVCodecContext  *pCodecCtx = NULL;
    AVCodec         *pCodec = NULL;
    AVFrame         *pFrame = NULL;
    AVPacket        packet;
    int             frameFinished;

    AVDictionary    *optionDict = NULL;
    struct SwsContext *sws_ctx = NULL;

    SDL_Overlay     *bmp = NULL;
    SDL_Surface     *screen = NULL;
    SDL_Rect        rect;
    SDL_Event       event;

    if(argc < 2){
        fprintf(stderr, "Usage: test <file> \n");
        exit(1);
    }

    av_register_all();

    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)){
        fprintf(stderr,"Could not initialize SDL - %s " + *SDL_GetError());
        exit(1);
    }

    /*
    *打开一个文件
    */
    if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0)
        return -1;

    /*
	 *为pFormatCtx->streams填充上正确的信息
	 */
    if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
        return -1;

    /*
	 *手工调试函数,将文件信息在终端输出
	 */
    av_dump_format(pFormatCtx, 0, argv[1], 0);


    videoStream=-1;
	for ( i = 0; i < pFormatCtx->nb_streams; i++)
	  if(pFormatCtx -> streams[i] -> codec -> codec_type == AVMEDIA_TYPE_VIDEO) {
	    videoStream = i;
	    break;
	  }

	if(videoStream == -1)
	  return -1;

    /*
     *从 vedio stream 中获取对应的解码器上下文的指针
     */
    pCodecCtx = pFormatCtx -> streams[videoStream] -> codec;

    /*
     *根据 codec_id 找到对应的解码器
     */
    pCodec = avcodec_find_decoder(pCodecCtx -> codec_id);

    if(pCodec == NULL){
        fprintf(stderr, "Unsupported codec ! \n");
        return -1;
    }

    /*
     * 打开解码器
     */
    if(avcodec_open2(pCodecCtx, pCodec, &optionDict) <0 )
        return -1;

    /*
     * 为frame 申请内存
     */
    pFrame = av_frame_alloc();

    #ifdef __DARWIN__
        screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
    #else
        screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 24, 0);
    #endif // __DARWIN__

    if(!screen){
        fprintf(stderr, "SDL : could not set video mode - exiting \n");
        exit(1);
    }

    /*
     * 申请一个 overlay , 将 yuv数据给 screen
     */
    bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen);

    sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
                             AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL);

    i = 0;
    while (av_read_frame(pFormatCtx, &packet) >= 0){

        if(packet.stream_index == videoStream){
            
            //为视频流解码
            avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

            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];

                sws_scale(sws_ctx, (uint8_t const * 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);
                SDL_Delay(10);

            }
        }

        av_free_packet(&packet);
        SDL_PollEvent(&event);

        switch (event.type) {

            case SDL_QUIT:
                SDL_Quit();
                exit(0);
                break;

            default:
                break;
        }

    }


    av_free(pFrame);

    avcodec_close(pCodecCtx);

    avformat_close_input(&pFormatCtx);

    return 0;
}

编译:

gcc -o playvedio playvedio.c -lavutil -lavformat -lavcodec -lavutil -lswscale -lSDL

运行:

./playvedio 文件路径+文件名

 

© 著作权归作者所有

共有 人打赏支持
曾经花田错
粉丝 5
博文 41
码字总数 39023
作品 0
海淀
程序员
学习FFmpeg API – 解码视频

ffmpeg是编解码的利器,用了很久,以前看过dranger 的教程,非常精彩,受益颇多,是学习ffmpeg api很好的材料。可惜的是其针对的ffmpeg版本已经比较老了,而ffmpeg的更新又很快,有些API已经...

霄霄月月
2012/05/08
0
32
FFmpeg深入分析之零-基础

FFmpeg是相当强大的多媒体编解码框架,在深入分析其源代码之前必须要有基本的多媒 体基础知识,否则其源代码会非常晦涩难懂。本文将从介绍一些基本的多媒体只是,主要是为研读ffmpeg源代码做...

李荣刚
2015/03/16
0
0
Twitch如何实现转码比FFmpeg性能提升65%?(下)

文 / Jeff Gong, Sahil Dhanju, Chih-Chiang Lu, Yueshi Shen 编者按:超过220万创作者在Twitch发布海量的视频,这对实时转码业务造成了巨大压力,Twitch团队通过优化多线程的转码服务以及I...

livevideostack
2017/12/13
0
0
FFmpeg深入分析之零-基础

FFmpeg是相当强大的多媒体编解码框架,在深入分析其源代码之前必须要有基本的多媒体基础知识,否则其源代码会非常晦涩难懂。本文将从介绍一些基本的多媒体只是,主要是为研读ffmpeg源代码做准...

天下杰论
2015/04/22
0
0
ffmpeg在windows下视频采集

ffmpeg视频采集功能非常强大,不仅可以采集视频采集卡或USB摄像头的图像,还可以进行屏幕录制,同时还支持以RTP方式将视频流传送给支持RTSP的流媒体服务器,支持直播应用。 ffmpeg在Linux下的...

WuHonghai
2011/11/18
0
0
FFMPEG命令行处理视频进阶——高阶必读

FFMPEG拥有强大的视频处理能力,可惜的是有很多人不知道如何使用。本文深入介绍如何用编译好ffmpeg.exe程序处理视频,既有常用的简单的处理,也有一些比较少见的高大上的处理,一定能让你受益...

zhangamxqun
05/13
0
0
通过FFmpeg解码和OpenGL的YUV转RGB实现Android视频播放

前言 在我的博文 https://blog.csdn.net/ericbar/article/details/80506390 中,我们在Android平台上,实现了通过FFmpeg在native(C/C++)层进行视频解码,并通过OpenGL实现了硬件渲染工作,...

ericbar
05/30
0
0
PHP中利用Ffmpeg获得flv视频缩略图和播放时间

这里简单说一下:FFmpeg是用于录制、转换和流化音频和视频的完整解决方案,一套领先的音/视频编解码类库。官方正式版ffmpeg不支持rmvb和rm格式. 不过有很多解决方法 FFmpeg的官方网址是 http...

5D同学
2012/04/16
0
0
centos上安装ffmpeg

FFmpeg介绍 FFmpeg是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的...

水墨如丹青
04/13
0
0
ffmpeg常用基本命令(转)

ffmpeg常用基本命令(转) 【FFmpeg】FFmpeg常用基本命令 1.分离视频音频流 ffmpeg -i inputfile -vcodec copy -an outputfile_video  //分离视频流ffmpeg -i inputfile -acodec copy -vn ou......

ffredy
2015/08/11
0
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

ES12-词项查询

1.词项查询介绍 全文查询将在执行之前分析查询字符串,但词项级别查询将按照存储在倒排索引中的词项进行精确操作。这些查询通常用于数字,日期和枚举等结构化数据,而不是全文本字段。 或者,...

贾峰uk
8分钟前
0
0
http状态码与ajax的状态值

ajax状态值 1.1 200 & OK:状态请求成功

litCabbage
11分钟前
0
0
iOS动画效果合集、飞吧企鹅游戏、换肤方案、画板、文字效果等源码

iOS精选源码 动画知识运用及常见动画效果收集 3D卡片拖拽卡片叠加卡片 iFIERO - FLYING PENGUIN 飞吧企鹅SpriteKit游戏(源码) Swift封装的空数据提醒界面EmptyView 沙盒文件浏览与分享调试控...

sunnyaigd
15分钟前
0
0
AngularJS配置.run()块中设置路由事件的监听器以及过滤未经授权的请求

AngularJS中的run方法初始化全局数据,只对全局作用域起作用,如$rootScope.多个控制器之间可以共享数据,如下代码所示: <script type="text/javascript"> var m1 = angular....

孟飞阳
15分钟前
0
0
Java语言学习(十):输入/输出

Java中,I/O操作代表着输入、输出,Java所有的I/O机制都是基于数据流进行输入输出。java.io类包提供了很多的输入输出处理功能方法,大家可以参考下JDK文档中关于I/O的一些处理方法:JDK在线中...

海岸线的曙光
24分钟前
0
0
基于阿里出得ng-Alain搭建后台管理系统

首先跟大家介绍一下ng_Alain(阿里团队出品) ng-alain技术栈基于 Typescript、Angular、g2、@delon 和 ng-zorro-antd,提前了解和学习这些知识会非常有帮助。 ng-alain 脚手架是基于 Angular ...

方宏春
29分钟前
1
0
Spring框架IOC和AOP的实现原理

一、IoC(Inversion of Control) (1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控。控制权由应用代码中转到了外部容器,控制权的转...

HaierBrother
31分钟前
1
0
C++模版编程实现Haskell的函数模式匹配特性[图]

C++模版编程实现Haskell的函数模式匹配特性[图]: 大神 Bartosz Milewski 在2009年写了一篇文章《What Does Haskell Have to Do with C++?》,使用C++实现Haskell函数式编程语言的一些特性。...

原创小博客
32分钟前
1
0
${value}

1、就算 mapper 里面配置的名称是configSql ,在xml 里面配置的时候要注意 报错:org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.Reflectio......

职业搬砖20年
38分钟前
1
0
Xamarin 学习笔记 - Layout(布局)

本文翻译自CodeProject文章:https://www.codeproject.com/Articles/1227733/Xamarin-Notes-Xamarin-Forms-Layouts 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案...

葡萄城技术团队
39分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部