本文主要基于Qt利用FFmpeg视频库完成对网络摄像头(H.264)视频流的解码、显示、格式转换及存储。
文章FFmpeg+Qt实现摄像头(rtsp)实时显示实现了摄像头视频流的解码及显示工作。
接下来就是视频格式转换,主要转换思路是:视频存储(YUV420P)—>H.264—>avi
采用以下方式,将解码后的一帧帧图像(YUV格式)存储到本地:
fwrite(pFrameYUV->data[0], 1, y_size, fp_yuv); //Y
fwrite(pFrameYUV->data[1], 1, y_size / 4, fp_yuv); //U
fwrite(pFrameYUV->data[2], 1, y_size / 4, fp_yuv); //V
其中,fp_yuv为存储文件““
YUV文件播放时需要专门的播放器,比如“YUV Player”。
此过程主要包含以下几个步骤:
if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) {
printf("Failed to open output file! \n");
return;
}
pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
if (!pCodec) {
printf("Can not find encoder! \n");
return;
}
if (avcodec_open2(pCodecCtx, pCodec, ¶m) < 0) {
printf("Failed to open encoder! \n");
return;
}
avformat_write_header(pFormatCtx, NULL);
av_new_packet(&pkt, picture_size);
y_size = pCodecCtx->width * pCodecCtx->height;
for (int i = 0; iRead raw YUV data
if (fread(picture_buf, 1, y_size * 3 / 2, in_file) <= 0) {
printf("Failed to read raw data! \n");
return;
}
else if (feof(in_file)) {
break;
}
pFrame->data[0] = picture_buf; // Y
pFrame->data[1] = picture_buf + y_size; // U
pFrame->data[2] = picture_buf + y_size * 5 / 4; // V
//PTS
//pFrame->pts=i;
pFrame->pts = i*(video_st->time_base.den) / ((video_st->time_base.num) * 25);
int got_picture = 0;
//Encode
int ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture);
if (ret < 0) {
printf("Failed to encode! \n");
exit(0);
}
if (got_picture == 1) {
printf("Succeed to encode frame: %5d\tsize:%5d\n", framecnt, pkt.size);
framecnt++;
pkt.stream_index = video_st->index;
ret = av_write_frame(pFormatCtx, &pkt);
av_free_packet(&pkt);
}
}
int flush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index) {
int ret;
int got_frame;
AVPacket enc_pkt;
if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &
AV_CODEC_CAP_DELAY))
return 0;
while (1) {
enc_pkt.data = NULL;
enc_pkt.size = 0;
av_init_packet(&enc_pkt);
ret = avcodec_encode_video2(fmt_ctx->streams[stream_index]->codec, &enc_pkt,
NULL, &got_frame);
av_frame_free(NULL);
if (ret < 0)
break;
if (!got_frame) {
ret = 0;
break;
}
printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n", enc_pkt.size);
/* mux encoded frame */
ret = av_write_frame(fmt_ctx, &enc_pkt);
if (ret < 0)
break;
}
return ret;
}
av_write_trailer(pFormatCtx);
直接在程序里调用了FFmpeg命令
system("ffmpeg -i ds.h264 -r 20 -s 512*288 -b:v 4000k output.avi");
完整的源码请见本人的git:[摄像头视频采集及存储系统] (https://gitee.com/git-lizhen/Camera_capture_and_save)