美文网首页FFmpegFFmpegffmpeg编解码技术及应用
ffmpeg入门教程之视频播放器原理和ffmpeg开发环境搭建以

ffmpeg入门教程之视频播放器原理和ffmpeg开发环境搭建以

作者: Vghh | 来源:发表于2019-10-03 22:08 被阅读0次

    文章目录

    • ffmpeg入门教程: https://www.jianshu.com/p/042c7847bd8a

    • 视频播放器原理

    • 如何阅读翻译官网文档?

    • ffmpeg官网文档

    • About FFmpeg

    • ffmpeg

    • ffplay

    • ffprobe

    • FFmpeg Libraries for developers

    • ffmpeg-API

    • libavformat

    • ffmpeg开发环境搭建(Windows)

    • Visual Studio 搭建ffmepg开发环境(Windows)

    • Visual Studio 编写ffmpeg封装格式转换器(无编解码)

    • GitHub:https://github.com/AnJiaoDe/FFmpegDemoVS

    • Clion 搭建ffmepg开发环境(Windows)

    • Clion 编写ffmpeg封装格式转换器(无编解码)

    • GitHub:https://github.com/AnJiaoDe/FFmpegDemo

    • 各位老铁有问题欢迎及时联系、指正、批评、撕逼

    ffmpeg入门教程https://www.jianshu.com/p/042c7847bd8a

    视频播放器原理

    ———————————————— 版权声明

    此处摘抄部分为CSDN博主「雷霄骅」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/leixiaohua1020/article/details/18893769

    视音频技术主要包含以下几点:封装技术,视频压缩编码技术以及音频压缩编码技术。如果考虑到网络传输的话,还包括流媒体协议技术。

    视频播放器播放一个互联网上的视频文件,需要经过以下几个步骤:解协议,解封装,解码视音频,视音频同步。如果播放本地文件则不需要解协议,为以下几个步骤:解封装,解码视音频,视音频同步。他们的过程如图所示。

    image.png

    解协议的作用

    就是将流媒体协议的数据,解析为标准的相应的封装格式数据。视音频在网络上传播的时候,常常采用各种流媒体协议,例如HTTP,RTMP,或是MMS等等。这些协议在传输视音频数据的同时,也会传输一些信令数据。这些信令数据包括对播放的控制(播放,暂停,停止),或者对网络状态的描述等。解协议的过程中会去除掉信令数据而只保留视音频数据。例如,采用RTMP协议传输的数据,经过解协议操作后,输出FLV格式的数据。

    解封装的作用

    就是将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。封装格式种类很多,例如MP4,MKV,RMVB,TS,FLV,AVI等等,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。例如,FLV格式的数据,经过解封装操作后,输出H.264编码的视频码流和AAC编码的音频码流。

    解码的作用

    就是将视频/音频压缩编码数据,解码成为非压缩的视频/音频原始数据。音频的压缩编码标准包含AAC,MP3,AC-3等等,视频的压缩编码标准则包含H.264,MPEG2,VC-1等等。解码是整个系统中最重要也是最复杂的一个环节。通过解码,压缩编码的视频数据输出成为非压缩的颜色数据,例如YUV420P,RGB等等;压缩编码的音频数据输出成为非压缩的音频抽样数据,例如PCM数据。

    视音频同步的作用

    就是根据解封装模块处理过程中获取到的参数信息,同步解码出来的视频和音频数据,并将视频音频数据送至系统的显卡和声卡播放出来。

    如何阅读翻译官网文档?

    • 必须具备基本的语法分析能力,能看懂主语从句、宾语从句、表语从句、定语从句、状语从句、同位语从句。参考:https://blog.csdn.net/weixin_34347651/article/details/93651259
    • 不必过于纠结某个单词的翻译,也不必过于纠结某个短语的翻译,过于纠结只会翻译出及其别扭的结果,有时候省略单词,省略短语,更换单词,更换短语,能翻译出更贴切上下文语境的结果。
    • 如果词汇量不过关的话,可借助金山词霸等工具,有时候机器翻译可能不准确,需要自行判断。

    ffmpeg官网文档

    官网链接:http://ffmpeg.org/

    About FFmpeg

    关于ffmpeg:

    FFmpeg is the leading multimedia framework, able to decode, encode, transcode, mux, demux, stream, filter and play pretty much anything that humans and machines have created. It supports the most obscure ancient formats up to the cutting edge. No matter if they were designed by some standards committee, the community or a corporation. It isalso highly portable: FFmpeg compiles, runs, and passes our testing infrastructure FATE across Linux, Mac OS X,Microsoft Windows, the BSDs, Solaris, etc. under a wide variety of build environments, machine architectures, and configurations.

    ffmpeg是领先的多媒体库,能够解码、编码、转码、封装、解封装、流操作、过滤和播放几乎所有人类和机器创造的东西。它支持最模糊的古老的格式,直到如今高端的多媒体格式。不管它们是由一些标准委员会、社区还是公司设计的,它也是高度可移植的:ffmpeg编译、运行、通过Linux、Macos x、Microsoft Windows、BSD、Solaris等多种构建环境、机器体系结构和配置测试。

    It contains libavcodec, libavutil, libavformat, libavfilter, libavdevice,libswscale and libswresample which can be used by applications.As well as ffmpeg, ffplay and ffprobe which can be used by end users for transcoding and playing.

    它包括以下这些供应用程序使用的库:libavcodec、libavutil、libavFormat、libavfilter、libavDevice、libswscale 和libswresSample。此外,提供了可供终端用户转码和播放的ffmpeg、ffplay和ffprobe 程序。

    ffmpeg

    A command line tool to convert multimedia files between formats

    转换多媒体文件格式的命令行工具

    ffplay

    A simple media player based on SDL and the FFmpeg libraries

    基于SDL和ffmpeg库的简易媒体播放器

    ffprobe

    A simple multimedia stream analyzer

    简单的多媒体流分析器

    FFmpeg Libraries for developers

    ffmpeg为开发者提供的库:

    libavutil is a library containing functions for simplifying programming, including random number generators, data structures, mathematics routines, core multimedia utilities, and much more.
    libavcodec is a library containing decoders and encoders for audio/video codecs.
    libavformat is a library containing demuxers and muxers for multimedia container formats.
    libavdevice is a library containing input and output devices for grabbing from and rendering to many common multimedia input/output software frameworks, including Video4Linux, Video4Linux2,VfW, and ALSA.
    libavfilter is a library containing media filters.
    libswscale is a library performing highly optimized image scaling and color space/pixel format conversion operations.
    libswresample is a library performing highly optimized audio resampling, rematrixing and sample format conversion operations.

    • libavutil:包含一系列简化编程的函数,如随机数生成、数据结构、数学计算、核心多媒体实用工具等。
    • libavcodec:包含音频/视频编解码器。
    • libavFormat:包含用于多媒体文件格式的封装器和解封装器
    • libavDevice:可以读取多媒体设备的数据,或者输出数据到指定的多媒体设备上。
    • libavfilter:包含媒体过滤器。
    • libswScale:执行高度优化的图像缩放和颜色空间/像素格式转换操作。
    • libswresSample:执行高度优化的音频重采样、重矩阵和采样格式转换操作。

    ffmpeg-API

    image image image.png

    libavformat

    简介

    I/O and Muxing/Demuxing Library.

    I/O和封装解封装库。(至于为何翻译封装,大可不必过于纠结,意思到位即可。你要是不喜欢这个词,换个词无所谓。)

    Libavformat (lavf) is a library for dealing with various media container formats. Its main two purposes are demuxing - i.e. splitting a media file into component streams, and the reverse process of muxing - writing supplied data in a specified container format. It also has an I/O module which supports a number of protocols for accessing the data (e.g. file, tcp, http and others). Unless you are absolutely sure you won't use libavformat's network capabilities, you should also call avformat_network_init().

    libavFormat(Lavf)是一个用于处理各种媒体容器格式的库。它的主要目的有两个,一个是解封装,即将媒体文件拆分为组件流;与之相反的是封装,将拆分出来的数据以指定的格式写入文件。它还有一个I/O模块,它支持许多访问数据的协议(例如文件、TCP、http等)。如果你要使用libavmat的网络功能,应该调用avFormat_network_init()。(除非您绝对确定不会使用libavmat的网络功能,否则还应该调用avFormat_network_init()。小编觉得括号里的翻译实在别扭。)

    A supported input format is described by an AVInputFormat struct, conversely an output format is described by AVOutputFormat. You can iterate over all input/output formats using the av_demuxer_iterate / av_muxer_iterate() functions. The protocols layer is not part of the public API, so you can only get the names of supported protocols with the avio_enum_protocols() function.

    AVInputFormat结构体定义了输入格式的某些属性,相反地,AVOutputFormat定义了输出格式的某些属性。可以使用av_demuxer_iterate/av_muxer_iterate()函数迭代所有输入/输出格式。协议层不是公共API的一部分,因此只能使用avio_enum_protocol()函数获取支持的协议的名称。

    Main lavf structure used for both muxing and demuxing is AVFormatContext, which exports all information about the file being read or written. As with most Libavformat structures, its size is not part of public ABI, so it cannot be allocated on stack or directly with av_malloc(). To create an AVFormatContext, use avformat_alloc_context() (some functions, like avformat_open_input() might do that for you).

    AVFormatContext是封装和解封装常用的结构体,它存储了读取、写入文件的所有信息。与大多数Libavformat 结构体一样,its size is not part of public ABI,(小编不了解ABI,在此先不翻译。清楚的朋友可下方留言讨论。),所有它无法直接在栈上分配内存,也不能直接调用av_malloc()函数分配内存。可使用avformat_alloc_context() 函数创建AVFormatContext结构体对象,(有些函数,比如,avformat_open_input()可以创建AVFormatContext结构体对象)。

    Most importantly an AVFormatContext contains:

    AVFormatContext 最重要的几个点:

    •the input or output format. It is either autodetected or set by user for input; always set by user for output.
    •an array of AVStreams, which describe all elementary streams stored in the file. AVStreams are typically referred to using their index in this array.
    •an I/O context. It is either opened by lavf or set by user for input, always set by user for output (unless you are dealing with an AVFMT_NOFILE format).

    ·一个AVStreams数组,它包含了存储在文件中的所有基本流。AVStream对象指向数组首地址(AVFormatContext 结构体中的AVStream **streams)。

    ffmpeg开发环境搭建(Windows)

    1.下载相关文件

    左边的windows builds是编译好的lib库等文件,可直接使用。右边是ffmpeg源码下载。

    image.png

    选择操作系统

    image.png

    下载dev和shared

    image.png

    dev下载最新的

    image.png

    shared下载最新的

    image.png

    2.dev目录结构

    image.png

    示例程序:

    image.png

    include头文件:

    image.png image.png

    lib文件:


    image.png

    3.shared目录结构

    image.png

    bin目录文件:

    image.png

    Visual Studio 搭建ffmepg开发环境(Windows)

    1.创建空项目FFmpegDemo

    image.png

    2.配置ffmpeg的include和lib

    在FFmpegDemo的根目录创建文件夹ffmpeg,(此步骤可随意,关键是为了配置include,lib)


    image.png

    将dev下的include文件夹和lib文件夹复制到创建的ffmpeg文件夹下


    image.png image.png

    将shared下的所有dll文件复制到FFmpegDemo/FFmpeg/Demo下


    image.png image.png image.png

    点击项目,再点击属性,点击VC++目录,选择平台,64位还是32位,点击包含目录右边的小三角形,再点击编辑

    image.png

    将ffmpeg的inlcude目录配置进去

    image.png

    将ffmpeg的lib目录配置进去


    image.png

    点击连接器下的输入,附加依赖项,将如下内容添加进去:

    avcodec.lib; avformat.lib; avutil.lib; avdevice.lib; 
    avfilter.lib;postproc.lib;swresample.lib; swscale.lib
    
    image.png

    环境搭建至此就收工了!

    Visual Studio 编写ffmpeg封装格式转换器(无编解码)

    下面,我们来完成一个格式转换的程序

    右击源文件,添加新建项,test.cpp(名称自己定)

    image.png

    在dev的examples目录中随便找一个示例程序(注意,这些都是C文件),比如找一个remuxing.c,多媒体文件格式转换程序

    image.png

    为方便测试,快速体验ffmpeg的乐趣,将红线报错的地方先注释,main()方法参数去掉

    image.png

    在FFmpegDemo下创建文件夹resources用于存放资源文件

    image.png
    image.png

    原来的

     in_filename  = argv[1];
     out_filename = argv[2];
    

    改成:

    in_filename = "../resources/video.avi";
    out_filename = "../resources/video.mp4";
    

    目的是为了将avi格式的视频文件转为mp4格式的视频文件,注意路径千万别写错了。

    然后很激动地点击run,注意debug/release,64/32,取决于开始的配置。

    image.png

    结果报错如下:


    image.png

    类型不兼容,强转一下即可;
    至于define__STDC_CONSTANT_MACROS,按照提示在文件前面添加如下代码即可:

    extern "C"
    {
    #ifdef __cplusplus
    #define __STDC_CONSTANT_MACROS
    
    #endif
    
    }
    

    注意:示例程序是C文件,我们创建的是CPP文件,最好在文件头引入的地方用extern "C"包起来:

    extern "C" {
    
    #include <libavutil/timestamp.h>
    #include <libavformat/avformat.h>
    
    }
    

    然后,点击run

    发现avi格式的视频转为了mp4格式的视频

    image.png

    注意:如果报错某某 已声明为被否决,是因为有一些函数,属性之类的,在源码中已经被标为废弃,

    可以设置SDL检查为否

    image.png

    test.cpp:

    /*
     * Copyright (c) 2013 Stefano Sabatini
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */
    
     /**
      * @file
      * libavformat/libavcodec demuxing and muxing API example.
      *
      * Remux streams from one container format to another.
      * @example remuxing.c
      */
    extern "C"
    {
    #ifdef __cplusplus
    #define __STDC_CONSTANT_MACROS
    
    #endif
    
    }
    extern "C" {
    
    #include <libavutil/timestamp.h>
    #include <libavformat/avformat.h>
    
    }
    
    static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
    {
        AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
    
        /*printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
            tag,
            av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
            av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
            av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
            pkt->stream_index);*/
    }
    
    int main()
    {
        AVOutputFormat *ofmt = NULL;
        AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
        AVPacket pkt;
        const char *in_filename, *out_filename;
        int ret;
        unsigned int  i;
        int stream_index = 0;
        int *stream_mapping = NULL;
        int stream_mapping_size = 0;
    
        /*if (argc < 3) {
            printf("usage: %s input output\n"
                "API example program to remux a media file with libavformat and libavcodec.\n"
                "The output format is guessed according to the file extension.\n"
                "\n", argv[0]);
            return 1;
        }*/
    
        in_filename = "../resources/video.avi";
        out_filename = "../resources/video.mp4";
    
        if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
            fprintf(stderr, "Could not open input file '%s'", in_filename);
            goto end;
        }
    
        if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
            fprintf(stderr, "Failed to retrieve input stream information");
            goto end;
        }
    
        av_dump_format(ifmt_ctx, 0, in_filename, 0);
    
        avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
        if (!ofmt_ctx) {
            fprintf(stderr, "Could not create output context\n");
            ret = AVERROR_UNKNOWN;
            goto end;
        }
    
        stream_mapping_size = ifmt_ctx->nb_streams;
        stream_mapping = (int *)av_mallocz_array(stream_mapping_size, sizeof(*stream_mapping));
        if (!stream_mapping) {
            ret = AVERROR(ENOMEM);
            goto end;
        }
    
        ofmt = ofmt_ctx->oformat;
    
        for (i = 0; i < ifmt_ctx->nb_streams; i++) {
            AVStream *out_stream;
            AVStream *in_stream = ifmt_ctx->streams[i];
            AVCodecParameters *in_codecpar = in_stream->codecpar;
    
            if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
                in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
                in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
                stream_mapping[i] = -1;
                continue;
            }
    
            stream_mapping[i] = stream_index++;
    
            out_stream = avformat_new_stream(ofmt_ctx, NULL);
            if (!out_stream) {
                fprintf(stderr, "Failed allocating output stream\n");
                ret = AVERROR_UNKNOWN;
                goto end;
            }
    
            ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
            if (ret < 0) {
                fprintf(stderr, "Failed to copy codec parameters\n");
                goto end;
            }
            out_stream->codecpar->codec_tag = 0;
        }
        av_dump_format(ofmt_ctx, 0, out_filename, 1);
    
        if (!(ofmt->flags & AVFMT_NOFILE)) {
            ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
            if (ret < 0) {
                fprintf(stderr, "Could not open output file '%s'", out_filename);
                goto end;
            }
        }
    
        ret = avformat_write_header(ofmt_ctx, NULL);
        if (ret < 0) {
            fprintf(stderr, "Error occurred when opening output file\n");
            goto end;
        }
    
        while (1) {
            AVStream *in_stream, *out_stream;
    
            ret = av_read_frame(ifmt_ctx, &pkt);
            if (ret < 0)
                break;
    
            in_stream = ifmt_ctx->streams[pkt.stream_index];
            if (pkt.stream_index >= stream_mapping_size ||
                stream_mapping[pkt.stream_index] < 0) {
                av_packet_unref(&pkt);
                continue;
            }
    
            pkt.stream_index = stream_mapping[pkt.stream_index];
            out_stream = ofmt_ctx->streams[pkt.stream_index];
            log_packet(ifmt_ctx, &pkt, "in");
    
            /* copy packet */
            pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
            pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
            pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
            pkt.pos = -1;
            log_packet(ofmt_ctx, &pkt, "out");
    
            ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
            if (ret < 0) {
                fprintf(stderr, "Error muxing packet\n");
                break;
            }
            av_packet_unref(&pkt);
        }
    
        av_write_trailer(ofmt_ctx);
    end:
    
        avformat_close_input(&ifmt_ctx);
    
        /* close output */
        if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
            avio_closep(&ofmt_ctx->pb);
        avformat_free_context(ofmt_ctx);
    
        av_freep(&stream_mapping);
    
        if (ret < 0 && ret != AVERROR_EOF) {
            //fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
            return 1;
        }
        system("pause");
        return 0;
    }
    
    

    GitHub:https://github.com/AnJiaoDe/FFmpegDemoVS

    视频文件没有上传,可自己pull下来添加文件进行测试。

    Clion 搭建ffmepg开发环境(Windows)

    小编相当喜欢JetBrains 风格开发工具,相当智能。
    Android开发用Android Studio
    JAVA开发用Intellj idea
    php开发用...
    python开发用...
    现在就向大家分享Clion 搭建ffmepg开发环境(Windows)。

    1.下载安装

    clion下载地址:http://www.jetbrains.com/clion/download/#section=windows

    image.png
    image.png

    2.按提示激活

    image.png

    3.配置环境

    如果你已经安装了VS,可以借助VS配置clion,
    点击file 的settings下面的Toolchains配置已经安装的VS路径

    image.png

    如果你没有安装VS,参考https://www.jianshu.com/p/1aa989808e15进行配置

    Clion 编写ffmpeg封装格式转换器(无编解码)

    配置如下:
    和VS配置一个意思,不再赘述

    image.png

    点击run,右边的正方形是stop

    image.png

    可以看到视频格式转换成功

    image.png

    GitHub:https://github.com/AnJiaoDe/FFmpegDemo

    各位老铁有问题欢迎及时联系、指正、批评、撕逼

    Github:https://github.com/AnJiaoDe

    简书:https://www.jianshu.com/u/b8159d455c69

    CSDN:https://blog.csdn.net/confusing_awakening

    ffmpeg入门教程:https://www.jianshu.com/p/042c7847bd8a

    微信公众号


    这里写图片描述

    QQ群

    这里写图片描述

    相关文章

      网友评论

        本文标题:ffmpeg入门教程之视频播放器原理和ffmpeg开发环境搭建以

        本文链接:https://www.haomeiwen.com/subject/cdodpctx.html