?方法聲明
extern "C" //ffmpeg使用c語言實(shí)現(xiàn)的,引入用c寫的代碼就要用extern
{
#include <libavcodec/avcodec.h> //注冊
#include <libavdevice/avdevice.h> //設(shè)備
#include <libavformat/avformat.h>
#include <libavutil/error.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}
#include<iostream>
class fcoverh264
{
public:
fcoverh264(int number);
//打開H264視頻文件
void openFile(std::string file);
//根據(jù)我們需要的封裝格式進(jìn)行處理
void outPut(std::string fileout);
private:
AVFormatContext* forContext, * formatout;//保存數(shù)據(jù)的結(jié)構(gòu)體 forContext存輸入進(jìn)來的視頻信息;formatout存儲最終輸出的視頻信息
AVPacket* pkt;//pkt
int videoType;
};
?定義實(shí)現(xiàn)?文章來源:http://www.zghlxwxcb.cn/news/detail-781860.html
#include "fcoverh264.h"
extern "C" //ffmpeg使用c語言實(shí)現(xiàn)的,引入用c寫的代碼就要用extern
{
#include <libavcodec/avcodec.h> //注冊
#include <libavdevice/avdevice.h> //設(shè)備
#include <libavformat/avformat.h>
#include <libavutil/error.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}
fcoverh264::fcoverh264(int number):videoType(number)
{
/*
* 轉(zhuǎn)碼的流程:
* 1.注冊組件
* 2.打開視頻流 打開視頻文件
* 3.查找有沒有流數(shù)據(jù)
* 4.查找視頻碼流數(shù)據(jù)
*
* 6.根據(jù)要的封裝格式 來猜測格式對應(yīng)編輯器
* 7.打開對應(yīng)文件
* 8.新建流
* 9.寫入頭部信息
* 10.讀取一幀一幀的碼流數(shù)據(jù)
* 11.轉(zhuǎn)碼---->時(shí)間基的轉(zhuǎn)化
* 所以在解碼的時(shí)候:顯示順序和解碼的順序是一樣的;
處理其他視頻的時(shí)候:就需要關(guān)注 顯示順序和解碼的順序是否一致了
編碼有B幀? 解碼:IPB
* 12.寫入對應(yīng)的一幀數(shù)據(jù)到文件中
*/
//注冊組件
av_register_all();
forContext = avformat_alloc_context();
}
void fcoverh264::openFile(std::string file)
{
//打開輸入視頻
int res = avformat_open_input(&forContext, file.c_str(), nullptr, nullptr);
//判斷是否打開成功
if (res < 0)
{
std::cout << "打開失敗"<<std::endl;
return;
}
//打開視頻文件成功,獲取文件信息
res = avformat_find_stream_info(forContext, nullptr);//查看有沒有相關(guān)視頻流信息
if (res < 0)//判斷是否有流媒體
{
std::cout << "沒有流媒體信息" << std::endl;
return;
}
//一個(gè)視頻流有多股碼流,存在forContentext中streams數(shù)組中
/*int videoType = -1;*/
for (int i = 0; i < forContext->nb_streams; i++) //i小于流的個(gè)數(shù)
{
if (forContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)//視頻流
{
videoType = i;//標(biāo)識類型
break;
}
}
if (videoType == -1)
{
std::cout << "沒有視頻流相關(guān)信息" << std::endl;
return;
}
std::cout << "輸入的準(zhǔn)備已經(jīng)完成"<<std::endl;
}
//根據(jù)我們需要的封裝格式進(jìn)行處理
void fcoverh264::outPut(std::string fileout)
{
//猜測編碼器
AVOutputFormat* avformat = av_guess_format(nullptr, fileout.c_str(), nullptr);
if (avformat == nullptr)
{
std::cout << "沒有編碼器!"<<std::endl;
return;
}
std::cout << "AVOutputFormat"<<std::endl;
//保存輸出視頻信息的結(jié)構(gòu)體
formatout = avformat_alloc_context();
//設(shè)置輸出格式
formatout->oformat = avformat;
//打開視頻流 文件流
//參數(shù)1:輸入輸出的上下文對象
//參數(shù)2:文件流路徑
//參數(shù)3:文件打開格式 寫的方式
int res = avio_open(&formatout->pb, fileout.c_str(), AVIO_FLAG_WRITE);
if (res < 0)
{
std::cout << "open file error"<<std::endl;
return;
}
std::cout << "avio_open"<<std::endl;
//新建視頻流
//參數(shù)1:視頻信息結(jié)構(gòu)體
//參數(shù)2:新建流 的 返回新建流 的地址
AVStream* newStream = avformat_new_stream(formatout, nullptr);
if (newStream == nullptr)
{
std::cout << "打開視頻流失敗"<<std::endl;
return;
}
std::cout << "newStream"<<std::endl;
//編碼器對應(yīng)參數(shù)設(shè)置 拷貝參數(shù)設(shè)置 newStream:輸入進(jìn)入流的參數(shù)設(shè)置
res = avcodec_parameters_copy(newStream->codecpar, forContext->streams[videoType]->codecpar);
std::cout << "res=" << res<<std::endl;
if (res < 0)
{
std::cout << "拷貝失?。?<< std::endl;
return;
}
std::cout << "res=" << res<<std::endl;
//設(shè)置新的流里面 codec_tag 設(shè)置為0
newStream->codecpar->codec_tag = 0;
//頭部信息寫入----寫入成功與否
res = avformat_write_header(formatout, nullptr);//formatout封裝格式的結(jié)構(gòu)體
//判斷寫入成功與否
if (res < 0)
{
std::cout << "寫入頭部信息失?。? <<std::endl;
return;
}
std::cout << "res=" << res << std::endl;
//開始讀取碼流數(shù)據(jù)
pkt = (AVPacket*)malloc(sizeof(AVPacket));
//算出這張圖有多大
int size = newStream->codecpar->width * newStream->codecpar->height;
av_new_packet(pkt, size);
int frameCount = 0;
//一幀一幀的讀取
while (av_read_frame(forContext, pkt) == 0)
{
//判斷這一幀這是不是視頻流
if (pkt->stream_index == videoType)
{
frameCount++;
//如果是視頻流----判斷有沒有設(shè)置過 時(shí)間基
if (pkt->pts == AV_NOPTS_VALUE)
{
//時(shí)間基 time_base AVRational屬性
AVRational timebase = forContext->streams[videoType]->time_base;
//計(jì)算幀之間的長度(duration) double強(qiáng)制轉(zhuǎn)換
int64_t duration = (double)AV_TIME_BASE / av_q2d(forContext->streams[videoType]->r_frame_rate);
//計(jì)算顯示時(shí)間基(pts):公式:(當(dāng)前幀數(shù)*兩幀之間的長度))/(輸入時(shí)間基*AV_TIME_BASE)
pkt->pts = (double)(frameCount * duration) / (av_q2d(timebase) * AV_TIME_BASE);
//解碼時(shí)間基(dts)
pkt->dts = pkt->pts;
//目標(biāo)兩幀之間的長度
pkt->duration = duration / (double)(av_q2d(timebase) * AV_TIME_BASE);
}
else if (pkt->pts < pkt->dts)//顯示 時(shí)間基 小于 解碼時(shí)間基 不要這樣子的
{
continue;
}
//上述步驟為 時(shí)間基設(shè)置
//解碼 時(shí)間基 真正的轉(zhuǎn)換 如下:
//顯示時(shí)間基的轉(zhuǎn)換
pkt->pts = av_rescale_q_rnd(pkt->pts, forContext->streams[videoType]->time_base,
newStream->time_base, (AVRounding)(AV_ROUND_INF | AV_ROUND_PASS_MINMAX));
//解碼時(shí)間基的轉(zhuǎn)換
pkt->dts = av_rescale_q_rnd(pkt->dts, forContext->streams[videoType]->time_base,
newStream->time_base, (AVRounding)(AV_ROUND_INF | AV_ROUND_PASS_MINMAX));
//數(shù)據(jù)時(shí)長設(shè)置
pkt->duration = av_rescale_q(pkt->duration, forContext->streams[videoType]->time_base,
newStream->time_base);
//數(shù)據(jù)位置的設(shè)置 數(shù)據(jù)在流信息中的設(shè)置
pkt->pos = -1;
//數(shù)據(jù)包的標(biāo)記:結(jié)合AV_PKT_FLAG_KEY使用 最小為1表示這一幀是一個(gè)關(guān)鍵幀
pkt->flags |= AV_PKT_FLAG_KEY;
//標(biāo)記:當(dāng)前寫入的這一幀是視頻流
pkt->stream_index = 0;
//轉(zhuǎn)碼后的數(shù)據(jù)包 寫入 目標(biāo)視頻信息 結(jié)構(gòu)體 中
av_interleaved_write_frame(formatout, pkt);
}
//清空處理:重新設(shè)置包
av_packet_unref(pkt);
}
//寫入尾巴幀
av_write_trailer(formatout);
//用完之后進(jìn)行 關(guān)閉 處理 :關(guān)閉猜測完的流
avio_close(formatout->pb);//對應(yīng)avio_open()
std::cout << "avio_close"<<std::endl;
//釋放malloc的空間 釋放保存信息的結(jié)構(gòu)體
av_free(formatout);
std::cout << "av_free"<<std::endl;
//關(guān)閉輸入流
avformat_close_input(&forContext);//對應(yīng)avformat_open_inpu
std::cout << "avformat_close_input"<<std::endl;
//釋放forContext結(jié)構(gòu)體空間
av_free(forContext);
std::cout << "av_free"<<std::endl;
}
?調(diào)用實(shí)例文章來源地址http://www.zghlxwxcb.cn/news/detail-781860.html
#include <iostream>
#include "fcoverh264.h"
int main() {
fcoverh264* cover = new fcoverh264{-1}; //轉(zhuǎn)碼
cover->openFile("test01.h264");
cover->outPut("code_frame.flv");
return 0;
}
到了這里,關(guān)于【FFMPEG應(yīng)用篇】基于FFmpeg的轉(zhuǎn)碼應(yīng)用(FLV MP4)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!