录制h264播放时遇到花屏问题
来源:11-9 实战NV12转YUV420P

邓丹俊
2025-02-10
老师好,我的摄像头数据是yuyv422的,用sws_scale转换为yuv420p后进行h264编码后发现yuv视频正常播放,但是h264播放花屏,且有报错,应该修改哪里的代码呢
代码如下:
extern “C”
{
#define __STDC_CONSTANT_MACROS 1
#include “libavutil/avutil.h”
#include “libavdevice/avdevice.h”
#include “libavformat/avformat.h”
#include “libavcodec/avcodec.h”
#include “libswresample/swresample.h”
#include “libavutil/audio_fifo.h”
#include “libavutil/imgutils.h”
#include “libswscale/swscale.h”
}
#include
#include
#include
#include
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::copy;
using std::ofstream;
using std::cout;
int main()
{
int ret{}, count{};
char err[1024];
ofstream file422,file264;
file422 = ofstream(“d:/video.yuv”, std::ios::trunc);
if (!file422)
return -1;
file422 << “”;
file422.close();
file264 = ofstream(“d:/video.h264”, std::ios::trunc);
if (!file264)
return -1;
file264 << “”;
file264.close();
file422 = ofstream(“d:/video.yuv”, std::ios::app);
if (!file422)
return -1;
file264 = ofstream(“d:/video.h264”, std::ios::app);
if (!file264)
return -1;
avdevice_register_all();
auto fmt = av_find_input_format("dshow");
if (!fmt)
{
cout << "av_find_input_format fail\n";
return -1;
}
AVFormatContext *ps{};
const char *url{ u8"video=Surface Camera Front" };
AVDictionary *options{};
ret = av_dict_set(&options, "video_size", "640x480",0);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "av_dict_set video_size:" << ret << ":" << err << "\n";
return -1;
}
ret = av_dict_set(&options, "framerate", "30", 0);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "av_dict_set framerate:" << ret << ":" << err << "\n";
return -1;
}
ret = av_dict_set(&options, "pix_fmt", "yuyv422", 0);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "av_dict_set pix_fmt:" << ret << ":" << err << "\n";
return -1;
}
ret = avformat_open_input(&ps,url,fmt,&options);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "avformat_open_input:" << ret << ":" << err << "\n";
return -1;
}
ret = avformat_find_stream_info(ps, nullptr);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "avformat_find_stream_info:" << ret << ":" << err << "\n";
return -1;
}
av_dump_format(ps, 0, url, 0);
///////////////////////////////////////////////////////////////
auto codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
cout << "avcodec_find_encoder fail\n";
return -1;
}
auto ctx = avcodec_alloc_context3(codec);
if (!ctx)
{
cout << "avcodec_alloc_context3 fail\n";
return -1;
}
ctx->width = 640;
ctx->height = 480;
ctx->gop_size = 250;
ctx->pix_fmt = AV_PIX_FMT_YUV420P;
ctx->profile = AV_PROFILE_H264_HIGH_444;
ctx->level = 50;
ctx->framerate = AVRational{ 25,1 };
ctx->time_base= AVRational{ 1,25 };
ret = av_opt_set(ctx->priv_data, "preset", "slow", 0);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "av_opt_set:" << ret << ":" << err << "\n";
return -1;
}
ret = avcodec_open2(ctx, codec, nullptr);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "avcodec_open2:" << ret << ":" << err << "\n";
return -1;
}
AVFrame *frame420,*frame422;
frame420 = av_frame_alloc();
if (!frame420)
{
cout << "av_frame_alloc frame420 fail\n";
return -1;
}
frame422 = av_frame_alloc();
if (!frame422)
{
cout << "av_frame_alloc frame422 fail\n";
return -1;
}
frame420->width = 640;
frame420->height = 480;
frame420->format = AV_PIX_FMT_YUV420P;
ret = av_frame_get_buffer(frame420, 32);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "av_frame_get_buffer frame420:" << ret << ":" << err << "\n";
return -1;
}
frame422->width = 640;
frame422->height = 480;
frame422->format = AV_PIX_FMT_YUYV422;
ret = av_frame_get_buffer(frame422, 32);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "av_frame_get_buffer frame422:" << ret << ":" << err << "\n";
return -1;
}
enum AVPixelFormat src_pix_fmt = AV_PIX_FMT_YUYV422;
enum AVPixelFormat dst_pix_fmt = AV_PIX_FMT_YUV420P;
int width = 640; // 图像宽度
int height = 480; // 图像高度
// 创建视频帧转换上下文 从YUYV422转换到YUV420P
SwsContext *sws_ctx = sws_getContext(width, height, src_pix_fmt,
width, height, dst_pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
if (!sws_ctx) {
cout<<"Could not initialize the conversion context\n";
return -1;
}
///////////////////////////////////////////////
AVPacket pkt[200],*newpkt;
newpkt = av_packet_alloc();
if (!newpkt)
{
cout << "av_packet_alloc fail\n";
return -1;
}
for (int i = 0; i != 200; ++i)
{
ret = av_read_frame(ps, &pkt[i]);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "av_read_frame:" << ret << ":" << err << "\n";
return -1;
}
}
avformat_close_input(&ps);
//307200 460800 76800 384000 460800 614400
for (int i = 0; i != 200; ++i)
{
//拷贝数据到yuyv422中 width*height*2 640*480*2
copy(pkt[i].data, pkt[i].data + 614400, frame422->data[0]);
//视频帧转换
ret = sws_scale(sws_ctx, frame422->data, frame422->linesize, 0, height,
frame420->data, frame420->linesize);
if (ret < 0)
{
av_strerror(ret, err, 1024);
cout << "sws_scale:" << ret << ":" << err << "\n";
return -1;
}
frame420->pts = i;
ret = avcodec_send_frame(ctx, frame420);
while (ret >= 0)
{
ret = avcodec_receive_packet(ctx, newpkt);
if (ret < 0)
break;
file264.write(reinterpret_cast<char*>(newpkt->data), newpkt->size);
}
file422.write(reinterpret_cast<char*>(pkt[i].data), 614400);
av_packet_unref(&pkt[i]);
}
ret = avcodec_send_frame(ctx, nullptr);
while (ret >= 0)
{
ret = avcodec_receive_packet(ctx, newpkt);
if (ret < 0)
break;
file264.write(reinterpret_cast<char*>(newpkt->data), newpkt->size);
}
sws_freeContext(sws_ctx);
av_packet_free(&newpkt);
av_frame_free(&frame422);
av_frame_free(&frame420);
file264.close();
file422.close();
av_log_set_level(AV_LOG_DEBUG);
av_log(nullptr, AV_LOG_INFO, "finish\n");
return 0;
}
yuv播放如下:
h264播放如下:
1回答
-
李超
2025-02-10
你将YUV422转成YUV420后有播放过吗,我估计你这步出错了
022025-02-10
相似问题