|
我视频格式信息大致如下:
[AppleScript] 纯文本查看 复制代码 [NULL @ 0x564aa13ec600] PPS id out of range: 0
[hevc @ 0x564aa13ec600] PPS id out of range: 0
[hevc @ 0x564aa13ec600] Error parsing NAL unit #0.
[hevc @ 0x564aa13ec600] PPS id out of range: 0
Last message repeated 1 times
[hevc @ 0x564aa13ec600] Error parsing NAL unit #0.
[hevc @ 0x564aa13ec600] PPS id out of range: 0
Last message repeated 1 times
[hevc @ 0x564aa13ec600] Error parsing NAL unit #0.
[hevc @ 0x564aa13ec600] PPS id out of range: 0
Last message repeated 1 times
[hevc @ 0x564aa13ec600] Error parsing NAL unit #0.
[hevc @ 0x564aa13ec600] PPS id out of range: 0
Last message repeated 1 times
[hevc @ 0x564aa13ec600] Error parsing NAL unit #0.
Input #0, mpeg, from xxxxx.mp4':
Duration: 00:23:39.85, start: 20018.316689, bitrate: 3024 kb/s
Stream #0:0[0x1e0]: Video: hevc (Main), yuv420p(tv), 2560x1536, 50 fps, 50 tbr, 90k tbn, 50 tbc
然后我使用如下的代码用ffmpeg把每一帧解出来转opencv Mat然后做处理,但是只能解出一半,比如视频总70590帧,最后只能解35295帧出来,但是换了其他别的h264 h265等mp4视频都是正常没问题的,这个是咋回事,大师兄知道要怎么修改这个代码嘛?使用的是海康威视的摄像头获取的监控视频。但是我使用这个命令:
[AppleScript] 纯文本查看 复制代码 ffmpeg -i xxxxx.mp4 -f image2 %d.jpg
却可以把全部帧完整解出来。
下面是我使用的只能解出一半帧的代码:
[C++] 纯文本查看 复制代码 /**
SZU FML lab
author:Jinlong Li
*
*/
#define __STDC_CONSTANT_MACROS
#include <stdio.h>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <iomanip>
#include <opencv/cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <experimental/filesystem>
#include <gflags/gflags.h>
/* 添加ffmpeg头文件 */
#include <math.h>
extern "C"
{
// 设置操作选项操作
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
// 用于音频声道布局操作
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
// 数学相关操作
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
// 封装和解封装操作
#include <libavformat/avformat.h>
// 用于缩放和转换颜色格式操作
#include <libswscale/swscale.h>
}
/* 获取时间然后对比 */
double what_time_is_it_now()
{
struct timeval time;
if (gettimeofday(&time,NULL)){
return 0;
}
return (double)time.tv_sec + (double)time.tv_usec * .000001;
}
int main(int argc, char **argv)
{
time_t t;
t = time(NULL);
std::cout << "Start time : " << ctime(&t);
double start_time = what_time_is_it_now();
/* register all the codecs */
/* 一般都是要函数内部初始化操作 */
av_register_all();
if (argc < 2) {
printf("usage: %s input_file\n"
"example: ./decoding_mp4.bin hello.mp4",
argv[0]);
exit(1);
}
/* 定义操作的上下文线索 */
AVFormatContext* pFormatCtx = NULL;
const char*filename = argv[1];
std::string videoName(filename);
//step 1:open file,get format info from file header
// 打开文件然后获取格式信息
if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0){
fprintf(stderr,"avformat_open_input");
exit(1);
}
//step 2:get stread info
// 这里输出视频流的信息
if (avformat_find_stream_info(pFormatCtx, NULL) < 0){
fprintf(stderr,"avformat_find_stream_info");
exit(1);
}
//just output format info of input file
av_dump_format(pFormatCtx, 0, filename, 0);
int videoStream = -1;
//step 3:find vido stream
// 找到视频流数据,然后输出相关信息,包括视频流的宽高,总帧数,帧率等
int stream_width, stream_heigth, fps;
long total_frames;
for (int i = 0; i < pFormatCtx->nb_streams; i++)
{
AVStream*in_stream = pFormatCtx->streams[i];
// fps = pFormatCtx->streams[i]->r_frame_rate;
fps = in_stream->avg_frame_rate.num / in_stream->avg_frame_rate.den;
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
stream_width = in_stream->codec->width;
stream_heigth = in_stream->codec->height;
total_frames = in_stream->nb_frames;
break;
}
}
/* 获取视频时间长度 */
long long video_duration;
if(pFormatCtx->duration > 0)
{
video_duration = pFormatCtx->duration / 1000LL;
}
else{
video_duration = 0;
}
long long check_total_frames = video_duration/1000*fps;
if(total_frames < check_total_frames)
{
total_frames = check_total_frames;
}
std::cout << "total_frames = " << total_frames << " fps = " << fps << std::endl;
if (videoStream == -1){
fprintf(stderr,"find video stream error");
exit(1);
}
AVCodecContext* pCodecCtxOrg = NULL;
AVCodecContext* pCodecCtx = NULL;
AVCodec* pCodec = NULL;
// 编解码
pCodecCtxOrg = pFormatCtx->streams[videoStream]->codec; // codec context
//step 4:find decoder
// 查找解码器
pCodec = avcodec_find_decoder(pCodecCtxOrg->codec_id);
std::cout << "pCoder : " << pCodec << std::endl;
if (!pCodec){
fprintf(stderr,"avcodec_find_decoder error");
exit(1);
}
//step 5:get one instance of AVCodecContext,decode need it.
pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_copy_context(pCodecCtx, pCodecCtxOrg) != 0){
fprintf(stderr,"avcodec_copy_context error");
exit(1);
}
//step 6: open codec
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0){
fprintf(stderr,"avcodec_open2 error");
exit(1);
}
AVFrame* pFrame = NULL;
AVFrame* pFrameRGB = NULL;
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
int numBytes = 0;
uint8_t* buffer = NULL;
/* 转换为和opencv对应的数据格式:AV_PIX_FMT_RGB24 */
numBytes = avpicture_get_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture*)pFrameRGB, buffer, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
struct SwsContext* sws_ctx = NULL;
/* 可以看作是sws_scale函数初始化函数 */
// std::cout << pCodecCtx->pix_fmt << std::endl;
// std::cout << AV_PIX_FMT_YUV420P << std::endl;
sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BILINEAR, NULL, NULL, NULL);
AVPacket packet;
long long i = 1;
//step 7:read frame
std::ofstream outfile;
/* 外面创建这个对象,避免每次循环都要创建一次 */
cv::Mat mRGB(cv::Size(pCodecCtx->width, pCodecCtx->height), CV_8UC3);
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
int frameFinished = 0;
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished)
{
/* 可以看作是sws_getContext函数的执行函数 */
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data, pFrame->linesize, 0,
pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
if (i <= total_frames)
{
//step 8:save frame
// mRGB.data = buffer;
/* 直接让Mat矩阵的头指针指向pFrameRGB可以更快些,避免了内存数据的拷贝 */
mRGB.data = (uchar*)pFrameRGB->data[0];
/* RGB格式转opencv BGR格式 */
// cv::cvtColor(mRGB, mRGB, cv::COLOR_RGB2BGR);
// select_ROI(mRGB);
std::cout << "process frame : " << i << std::endl;
i++;
if(i > total_frames)
break;
}
}
}
//release resource
av_free_packet(&packet);
av_free(buffer);
av_frame_free(&pFrameRGB);
av_frame_free(&pFrame);
avcodec_close(pCodecCtx);
avcodec_close(pCodecCtxOrg);
// sws_freeContent(sws_ctx);
avformat_close_input(&pFormatCtx);
double all_time = what_time_is_it_now() - start_time;
return 0;
}
还请大师兄可以解答下~~
|
|