FFmpeg学习.md 6.1 KB

##FFmpeg库学习相关

win下涉及环境设置挺简单 下载ffmpeg预编译好得链接库 项目设置lib include目录引用 用到啥库引用啥lib文件就好

关于文档 官网没有SDK API类文档 项目开源 代码注释都在源码中 .H文件就是文档 并且符合doxygen得规范 我用doxygen工具导出就能生存html得手册 比较好用

主要是没有示例 所以即使有API文档 没有处理视频得经验 并不确定H264视频得传输方式 需要初始化什么获得什么 这可能是需要补充学习得资料 目前项初期就只用来获取摄像头得视频来源流推 核心示例代码已经包含推流全部得流程思路 细节不一样参考doxygen生成得文档 示例是从文件流获取信息转为流推 实际需要获取摄像头得输入流
这里需要看摄像头接入方式 为产品设计考虑 应该支持所有即插即用得USB摄像头 并且自己定制一款摄像头模组封装成自己得摄像头 走肯定走USB接口 实际可能是串口数据或者其他类型 USB摄像头如果非专业监控或者网络摄像头 不会有带类似rtsp得流视频数据库采集进入 大概率是 RGB或者YUY2,MJPEG等格式 未经压缩得 类似从本地文件打开得媒体信息 需要研究如何填充 输入流得 AVFormatContext 结构数据 如何转码同步 暂无示例需要文档研究或者继续找示例 余下得核心部分是图形处理 美颜 水印 自动人脸打码等 是按单帧得图形处理 用得opencv库 opencv是基于ffmpeg开发得一个更大型很多得库 美颜相关得图形处理都靠他

示例代码版本比较旧仅供参考 核心示例代码

/*******************************************************************************
**                                                                            **
**                     Jiedi(China nanjing)Ltd.                               **
**                 创建:夏曹俊,此代码可用作为学习参考                       **
*******************************************************************************/

/*****************************FILE INFOMATION***********************************
**
**  Project       : FFmpegSDK实战课程
**  Description   : 基于FFMpegSDK的实战课程
**  Contact       : xiacaojun@qq.com
**  博客   : http://blog.csdn.net/jiedichina
**  视频课程
**  http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=961
**  http://edu.51cto.com/lecturer/12016059.html
**  http://study.163.com/u/xiacaojun
**  https://jiedi.ke.qq.com/
**  购买课程后可以加群咨询课程学习问题
**  群号 132323693 fmpeg的直播推流课程
**  微信公众号  : jiedi2007
**  头条号  : 夏曹俊
**
*******************************************************************************/

extern "C"
{
#include "libavformat/avformat.h"
#include "libavutil/time.h"
}
#include <iostream>
using namespace std;
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")

int XError(int errNum)
{
    char buf[1024] = { 0 };
    av_strerror(errNum, buf, sizeof(buf));
    cout << buf << endl;
    getchar();
    return -1;
}
int main(int argc, char *argv[])
{

    char *inUrl = "test.flv";
    char *outUrl = "rtmp://192.168.1.44/live";

    //初始化所有封装和解封装 flv mp4 mov mp3
    av_register_all();

    //初始化网络库
    avformat_network_init();

    //////////////////////////////////////////////////////////////////////////
    //输入流 1 打开文件,解封装
    //输入封装上下文
    AVFormatContext *ictx = NULL;

    //打开文件,解封文件头
    int re = avformat_open_input(&ictx, inUrl, 0, 0);
    if (re != 0)
    {
        return XError(re);
    }
    cout << "open file " << inUrl << " Success." << endl;

    //获取音频视频流信息 ,h264 flv
    re = avformat_find_stream_info(ictx, 0);
    if (re != 0)
    {
        return XError(re);
    }
    av_dump_format(ictx, 0, inUrl, 0);
    //////////////////////////////////////////////////////////////////////////


    //////////////////////////////////////////////////////////////////////////
    //输出流 

    //创建输出流上下文
    AVFormatContext *octx = NULL;
    re = avformat_alloc_output_context2(&octx, 0, "flv", outUrl);
    if (!octx)
    {
        return XError(re);
    }
    cout << "octx create success!" << endl;

    //配置输出流
    //遍历输入的AVStream
    for (int i = 0; i < ictx->nb_streams; i++)
    {
        //创建输出流
        AVStream *out = avformat_new_stream(octx, ictx->streams[i]->codec->codec);
        if (!out)
        {
            return XError(0);
        }
        //复制配置信息,同于MP4
        //re = avcodec_copy_context(out->codec, ictx->streams[i]->codec);
        re = avcodec_parameters_copy(out->codecpar, ictx->streams[i]->codecpar);
        out->codec->codec_tag = 0;
    }
    av_dump_format(octx, 0, outUrl, 1);
    //////////////////////////////////////////////////////////////////////////


    //rtmp推流

    //打开io
    re = avio_open(&octx->pb, outUrl, AVIO_FLAG_WRITE);
    if (!octx->pb)
    {
        return XError(re);
    }

    //写入头信息
    re = avformat_write_header(octx, 0);
    if (re < 0)
    {
        return XError(re);
    }
    cout << "avformat_write_header " << re << endl;
    AVPacket pkt;
    for (;;)
    {
        re = av_read_frame(ictx, &pkt);
        if (re != 0)
        {
            break;
        }
        cout << pkt.pts << " " << flush;
        //计算转换pts dts
        AVRational itime = ictx->streams[pkt.stream_index]->time_base;
        AVRational otime = octx->streams[pkt.stream_index]->time_base;
        pkt.pts = av_rescale_q_rnd(pkt.pts, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));
        pkt.dts = av_rescale_q_rnd(pkt.pts, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));
        pkt.duration = av_rescale_q_rnd(pkt.duration, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));
        pkt.pos = -1;

        //视频帧推送速度
        if (pkt.stream_index == 0)
            av_usleep(30*1000);

        re = av_interleaved_write_frame(octx, &pkt);
        if (re<0)
        {
            return XError(re);
        }
    }

    cout << "file to rtmp test" << endl;
    getchar();
    return 0;
}