AVFrame *m_pFrameEncodeYUV1 = NULL;
uint8_t *m_VideoEncodebuffer1 = NULL;
struct SwsContext *m_pAddVideoConvert_ctx1 = NULL;
int m_iOutWidth = 1280;
int m_iOutHeight = 720;
for (;;)
{
int re = av_read_frame(ic, pkt);
if (re != 0)
{
break;
}
AVCodecContext *cc = 0;
if (pkt->stream_index == videoStream)
{
cc = vc;
}
if (pkt->stream_index == audioStream)
{
cc = ac;
}
///解码视频
//发送packet到解码线程 send传NULL后调用多次receive取出所有缓冲帧
re = avcodec_send_packet(cc, pkt);
if (re != 0)
{
XError(re);
continue;
}
av_packet_unref(pkt);
long long startTime = av_gettime();
for (;;)
{
//从线程中获取解码接口,一次send可能对应多次receive
re = avcodec_receive_frame(cc, frame2);
if (re != 0) {
break;
}
//视频
if (cc == vc)
{
m_pFrameEncodeYUV1 = av_frame_alloc();
m_VideoEncodebuffer1 = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, m_iOutWidth, m_iOutHeight));
avpicture_fill((AVPicture *)m_pFrameEncodeYUV1, m_VideoEncodebuffer1, AV_PIX_FMT_YUV420P, m_iOutWidth, m_iOutHeight);
m_pFrameEncodeYUV1->width = m_iOutWidth;
m_pFrameEncodeYUV1->height = m_iOutHeight;
m_pFrameEncodeYUV1->format = AV_PIX_FMT_YUV420P;
if (!m_pAddVideoConvert_ctx1)
{
m_pAddVideoConvert_ctx1 = sws_getContext(frame2->width, frame2->height,
AV_PIX_FMT_YUV420P, m_iOutWidth, m_iOutHeight, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
}
sws_scale(m_pAddVideoConvert_ctx1, frame2->data, frame2->linesize, 0, frame2->height, m_pFrameEncodeYUV1->data, m_pFrameEncodeYUV1->linesize);
//自测
//int y_size = frame2->width*frame2->height;
//fwrite(frame2->data[0], 1, y_size, yuv_file2); //Y
//fwrite(frame2->data[1], 1, y_size / 4, yuv_file2); //U
//fwrite(frame2->data[2], 1, y_size / 4, yuv_file2); //V
//Sleep(20);
m_muxVideo1.lock();
m_qAVFrameVideo1.push(m_pFrameEncodeYUV1);
m_qAVFrameBuffer1.push(m_VideoEncodebuffer1);
m_bFlagStart = true;
m_muxVideo1.unlock();
Sleep(200);
}
else if (cc == ac)//音频
{
//cout << "Audio" << endl;
}
}
}
cout << "m_qAVFrameVideo end" << endl;
} void EncodeVideoFrame::startEncode() { AVDictionary *opts = NULL; int re = avformat_open_input(&ic, path.c_str(), 0, &opts); if (re != 0) { XError(re); return; } re = avformat_find_stream_info(ic, 0); int totalMs = ic->duration / (AV_TIME_BASE / 1000); videoStream = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);; audioStream = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);;
AVCodec *vcodec = avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);
if (!vcodec)
{
cout << "can't find the codec id " << ic->streams[videoStream]->codecpar->codec_id;
getchar();
return;
}
cout << "find the AVCodec " << ic->streams[videoStream]->codecpar->codec_id << endl;
vc = avcodec_alloc_context3(vcodec);
///配置解码器上下文参数
avcodec_parameters_to_context(vc, ic->streams[videoStream]->codecpar);
//八线程解码
vc->thread_count = 8;
///打开解码器上下文
re = avcodec_open2(vc, 0, 0);
if (re != 0)
{
XError(re);
getchar();
return;
}
///音频解码器打开
acodec = avcodec_find_decoder(ic->streams[audioStream]->codecpar->codec_id);
if (!acodec)
{
cout << "can't find the codec id " << ic->streams[audioStream]->codecpar->codec_id;
getchar();
return;
}
cout << "find the AVCodec " << ic->streams[audioStream]->codecpar->codec_id << endl;
///创建解码器上下文呢
ac = avcodec_alloc_context3(acodec);
///配置解码器上下文参数
avcodec_parameters_to_context(ac, ic->streams[audioStream]->codecpar);
//八线程解码
ac->thread_count = 8;
///打开解码器上下文
re = avcodec_open2(ac, 0, 0);
if (re != 0)
{
XError(re);
return;
}
cout << "audio avcodec_open2 success!" << endl;
m_pVideoThread = new std::thread(LocalVideoThread, this);
return;
}
DecodeVideoFrame编码类
头文件 #pragma once #include #include #include #include using namespace std; class AVFrame; class AVFormatContext; class AVCodecContext; class AVCodec; class AVCodecContext; class AVStream; /* 完成视频帧的编码 */ class DecodeVideoFrame { public: DecodeVideoFrame(); ~DecodeVideoFrame(); bool m_bencode_video = false; bool m_bencodeEnd_video = false; int initVideo(); void DoDecodeVideo(); std::thread *m_pVideoDecodeThread = NULL; mutex m_muxDecodeVideo; queue<AVFrame *> m_qAVFrameDecodeVideo; queue<uint8_t *> m_qAVFrameDecodeBuffer; private: AVFormatContext *m_pFormatCtx = NULL; AVCodecContext *m_pVideoCodecCtx = NULL; AVCodec *m_pVideoCodec = NULL;
AVStream *m_pVideo_st = NULL;
int64_t m_first_vid_time1 = -1;
int64_t m_first_vid_time2 = -1;
AVFrame *m_pFrameDecodeYUV2 = NULL;
uint8_t * m_VideoDecodebuffer = NULL;
struct SwsContext *m_pAddVideoConvert_ctx1 = NULL;
int m_iOutWidth = 1280;
int m_iOutHeight = 720;
std::string m_strRecordPath = "111.mp4";
};
cpp文件 #include "DecodeVideoFrame.h" #include<windows.h> #ifdef __cplusplus extern "C" { #endif // !__cplusplus #include "libavutil/opt.h" #include <libavutil/imgutils.h> #include <libavformat/avformat.h> #include <libavformat/avio.h> #include "libavutil/time.h" #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> #include "libswresample/swresample.h"//包含头文件 #include <libavutil/imgutils.h> #ifdef __cplusplus } #endif // !__cplusplus
DecodeVideoFrame::DecodeVideoFrame() { }
DecodeVideoFrame::~DecodeVideoFrame() { } void VideoEncodeThread(void *param) { DecodeVideoFrame *pMan = (DecodeVideoFrame *)param; if (pMan) pMan->DoDecodeVideo(); } int DecodeVideoFrame::initVideo() { av_register_all(); avcodec_register_all(); AVCodecID m_video_codec_id = AV_CODEC_ID_H264; avformat_alloc_output_context2(&m_pFormatCtx, NULL, NULL, m_strRecordPath.c_str()); m_pVideoCodec = avcodec_find_encoder(m_video_codec_id); if (!m_pVideoCodec) { return false; }
m_pVideoCodecCtx = avcodec_alloc_context3(m_pVideoCodec);
m_pVideoCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
m_pVideoCodecCtx->codec_id = m_pVideoCodec->id;
m_pVideoCodecCtx->width = m_iOutWidth;// 1280;
m_pVideoCodecCtx->height = m_iOutHeight;// 720;
m_pVideoCodecCtx->time_base.num = 1;
m_pVideoCodecCtx->time_base.den = 25;
m_pVideoCodecCtx->bit_rate = 2000000;
m_pVideoCodecCtx->gop_size = 60;
m_pVideoCodecCtx->max_b_frames = 0;
m_pVideoCodecCtx->b_frame_strategy = 0;
AVDictionary *param = NULL;
if (m_video_codec_id == AV_CODEC_ID_H264)
{
m_pVideoCodecCtx->qmin = 10;
m_pVideoCodecCtx->qmax = 51;
av_dict_set(¶m, "preset", "ultrafast", 0);
av_dict_set(¶m, "tune", "zerolatency", 0);
}
if (avcodec_open2(m_pVideoCodecCtx, m_pVideoCodec, ¶m) < 0)
{
return false;
}
m_pVideo_st = avformat_new_stream(m_pFormatCtx, m_pVideoCodec);
if (m_pVideo_st == NULL)
{
return false;
}
avcodec_parameters_from_context(m_pVideo_st->codecpar, m_pVideoCodecCtx);
m_pVideo_st->time_base.num = 1;
m_pVideo_st->time_base.den = 25;
m_pVideo_st->codec = m_pVideoCodecCtx;
if (avio_open(&m_pFormatCtx->pb, m_strRecordPath.c_str(), AVIO_FLAG_READ_WRITE) < 0)
{
return false;
}
m_first_vid_time1 = -1;//要进行初始化 否则第二次时间戳会有问题
m_first_vid_time2 = -1;
m_pFrameDecodeYUV2 = av_frame_alloc();
m_VideoDecodebuffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, m_iOutWidth, m_iOutHeight));
avpicture_fill((AVPicture *)m_pFrameDecodeYUV2, m_VideoDecodebuffer, AV_PIX_FMT_YUV420P, m_iOutWidth, m_iOutHeight);
m_pFrameDecodeYUV2->width = m_iOutWidth;
m_pFrameDecodeYUV2->height = m_iOutHeight;
m_pFrameDecodeYUV2->format = AV_PIX_FMT_YUV420P;
AVDictionary* opt = NULL;
if (avformat_write_header(m_pFormatCtx, &opt) < 0)
{
return false;
}
m_pVideoDecodeThread = new std::thread(VideoEncodeThread, this);
}
void DecodeVideoFrame::DoDecodeVideo() { int ret; AVFrame *frameTemp = NULL; uint8_t *Video1bufferTemp = NULL; int nCount = 0; AVRational time_base_q = { 1, AV_TIME_BASE }; AVPacket enc_pkt; while (1) { //编码 m_first_vid_time1 = av_gettime(); m_muxDecodeVideo.lock(); if (m_bencodeEnd_video) { break; } if (m_bencode_video == false || m_qAVFrameDecodeVideo.size() == 0) { m_muxDecodeVideo.unlock(); Sleep(1000); continue; }
frameTemp = m_qAVFrameDecodeVideo.front();
Video1bufferTemp = m_qAVFrameDecodeBuffer.front();
m_qAVFrameDecodeVideo.pop();
m_qAVFrameDecodeBuffer.pop();
m_muxDecodeVideo.unlock();
if (!m_pAddVideoConvert_ctx1)
{
m_pAddVideoConvert_ctx1 = sws_getContext(frameTemp->width, frameTemp->height,
AV_PIX_FMT_YUV420P, m_iOutWidth, m_iOutHeight, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
}
sws_scale(m_pAddVideoConvert_ctx1, frameTemp->data, frameTemp->linesize, 0, frameTemp->height, m_pFrameDecodeYUV2->data, m_pFrameDecodeYUV2->linesize);
av_frame_free(&frameTemp);
av_free(Video1bufferTemp);
enc_pkt.data = NULL;
enc_pkt.size = 0;
av_init_packet(&enc_pkt);
int enc_got_frame = 0;
ret = avcodec_encode_video2(m_pVideoCodecCtx, &enc_pkt, m_pFrameDecodeYUV2, &enc_got_frame);
if (enc_got_frame == 1)
{
if (m_first_vid_time2 == -1)
m_first_vid_time2 = m_first_vid_time1;
enc_pkt.stream_index = m_pVideo_st->index;
enc_pkt.dts = enc_pkt.pts = (int64_t)(m_pVideo_st->time_base.den * (m_first_vid_time1 - m_first_vid_time2) / AV_TIME_BASE);
//m_muxFormat.lock(); 有音频有视频的时候裸流时需要
ret = av_interleaved_write_frame(m_pFormatCtx, &enc_pkt);
//m_muxFormat.unlock();
if (ret < 0)
{
av_packet_unref(&enc_pkt);
}
av_free_packet(&enc_pkt);
}
else
{
av_free_packet(&enc_pkt);
}
//av_frame_unref(m_pFrameFilterYUV);
//std::cout << "视频拼接视频" << enc_pkt.pts << endl;
}
if (m_pFormatCtx != NULL)
{
av_write_trailer(m_pFormatCtx);
}
Sleep(200);
return;
}
main函数
#include #include #include<windows.h> #ifdef __cplusplus extern "C" { #endif // !__cplusplus #include "libavutil/opt.h" #include <libavutil/imgutils.h> #include <libavformat/avformat.h> #include <libavformat/avio.h> #include "libavutil/time.h" #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> #include "libswresample/swresample.h"//包含头文件 #include <libavutil/imgutils.h> #ifdef __cplusplus } #endif // !__cplusplus #pragma comment(lib,"avformat.lib")//添加库文件,也可以在属性处添加 #pragma comment(lib,"avutil.lib") #pragma comment(lib,"avcodec.lib") #pragma comment(lib,"swresample.lib") #pragma comment(lib,"swscale.lib") #include #include #include "EncodeVideoFrame.h" #include "DecodeVideoFrame.h" using namespace std; #define _CRT_SECURE_NO_WARNINGS; int XError(int errNum) { char buf[1024] = { 0 }; av_strerror(errNum, buf, sizeof(buf));//ffmpeg中打印错误信息 cout << buf << endl; getchar(); return -1; } static double r2d(AVRational r) { return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den; } FILE *yuv_file3 = fopen("D:\yuv_file13.yuv", "wb");
int main(int argc, char *argv[]) { av_register_all(); avformat_network_init(); avcodec_register_all(); DecodeVideoFrame decodeVideo; decodeVideo.initVideo(); //m_pVideo1Thread = new std::thread(LocalVideoThread); //m_pVideo2Thread = new std::thread(LocalVideo2Thread); EncodeVideoFrame encodeVideo1; encodeVideo1.path = "01.mp4"; encodeVideo1.startEncode(); Sleep(200); EncodeVideoFrame encodeVideo2; encodeVideo2.path = "lane.avi"; encodeVideo2.startEncode(); //Sleep(200);
int m_iOutWidth = 2560;
int m_iOutHeight = 720;
uint8_t *tempBuff1 = NULL;
uint8_t *tempBuff2 = NULL;
//用这种方法保证队列中都有解码好的视频帧
cout << "Audio0" << endl;
for (; ; )
{
encodeVideo1.m_muxVideo1.lock();
if (encodeVideo1.m_bFlagStart == false)
{
encodeVideo1.m_muxVideo1.unlock();
Sleep(200);
continue;
}
encodeVideo1.m_muxVideo1.unlock();
break;
}
cout << "Audio1" << endl;
for (; ; )
{
encodeVideo2.m_muxVideo1.lock();
if (encodeVideo2.m_bFlagStart == false)
{
encodeVideo2.m_muxVideo1.unlock();
Sleep(200);
continue;
}
encodeVideo2.m_muxVideo1.unlock();
break;
}
cout << "Audio2" << endl;
for (;;)
{
cout << "Audio3" << endl;
Sleep(200);
encodeVideo1.m_muxVideo1.lock();
encodeVideo2.m_muxVideo1.lock();
if (encodeVideo1.m_qAVFrameVideo1.size() == 0 || encodeVideo2.m_qAVFrameVideo1.size() == 0)//视频帧都没了则表示有文件拼接结束了
{
encodeVideo2.m_muxVideo1.unlock();
encodeVideo1.m_muxVideo1.unlock();
decodeVideo.m_muxDecodeVideo.lock();
decodeVideo.m_bencodeEnd_video = true;
decodeVideo.m_muxDecodeVideo.unlock();
break;
}
tempBuff2 = encodeVideo2.m_qAVFrameBuffer1.front();
AVFrame * frame2 = encodeVideo2.m_qAVFrameVideo1.front();
encodeVideo2.m_qAVFrameBuffer1.pop();
encodeVideo2.m_qAVFrameVideo1.pop();
encodeVideo2.m_muxVideo1.unlock();
tempBuff1 = encodeVideo1.m_qAVFrameBuffer1.front();
AVFrame * frame = encodeVideo1.m_qAVFrameVideo1.front();
encodeVideo1.m_qAVFrameBuffer1.pop();
encodeVideo1.m_qAVFrameVideo1.pop();
encodeVideo1.m_muxVideo1.unlock();
AVFrame *m_pFrameEncodeYUV2 = av_frame_alloc();
uint8_t * m_VideoEncodebuffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, m_iOutWidth, m_iOutHeight));
avpicture_fill((AVPicture *)m_pFrameEncodeYUV2, m_VideoEncodebuffer, AV_PIX_FMT_YUV420P, m_iOutWidth, m_iOutHeight);
m_pFrameEncodeYUV2->width = m_iOutWidth;
m_pFrameEncodeYUV2->height = m_iOutHeight;
m_pFrameEncodeYUV2->format = AV_PIX_FMT_YUV420P;
cout << "Audio4" << endl;
for (int i = 0; i < m_iOutHeight; i++)
{
memcpy(m_pFrameEncodeYUV2->data[0] + (i)*m_iOutWidth, frame->data[0] + i*frame->width, frame->width);
memcpy(m_pFrameEncodeYUV2->data[0] + (i)*m_iOutWidth + frame->width, frame2->data[0] + i*frame2->width, frame2->width);
}
int iHeightHlaf = m_iOutHeight / 2;
int iWidthHlaf = m_iOutWidth / 2;
int iWidth1Hlaf = frame->width / 2;
int iWidth2Hlaf = frame2->width / 2;
for (int i = 0; i < iHeightHlaf; i++)
{
memcpy(m_pFrameEncodeYUV2->data[1] + (i)*(iWidthHlaf), frame->data[1] + i*(iWidth1Hlaf), (iWidth1Hlaf));
memcpy(m_pFrameEncodeYUV2->data[1] + (i)*(iWidthHlaf)+(iWidth1Hlaf), frame2->data[1] + i*(iWidth2Hlaf), (iWidth2Hlaf));
memcpy(m_pFrameEncodeYUV2->data[2] + (i)*(iWidthHlaf), frame->data[2] + i*(iWidth1Hlaf), (iWidth1Hlaf));
memcpy(m_pFrameEncodeYUV2->data[2] + (i)*(iWidthHlaf)+(iWidth1Hlaf), frame2->data[2] + i*(iWidth2Hlaf), (iWidth2Hlaf));
}
av_frame_free(&frame);
av_frame_free(&frame2);
av_free(tempBuff1);
av_free(tempBuff2);
cout << "Audio6" << endl;