在做一个数据通道
要求有两个
1.支持打开实时流,解码得到图片
2.支持打开视频文件,得到解码图片
第一个要求前任已经实现
bool FfmpegStreamChr::Open(const char *pstrFilename)
{
Close();
avformat_network_init();
av_register_all(); std::string tempfile = pstrFilename;
AVDictionary* options = NULL;
if (tempfile.size() > )
{
if (memcmp(tempfile.c_str() + tempfile.size() - , "#tcp", ) == )
{
av_dict_set(&options, "rtsp_transport", "tcp", );
tempfile.erase(tempfile.size() - );
}
} //format_context_ = avformat_alloc_cotext(); av_dict_set(&options, "stimeout","", );
if (avformat_open_input(&format_context_, tempfile.c_str(), NULL, &options) < )
return false; if (avformat_find_stream_info(format_context_, nullptr) < )
return false; av_dump_format(format_context_, , tempfile.c_str(), ); video_stream_index_ = -; pts_first = true;
duration = format_context_->duration / AV_TIME_BASE; int video_stream_idx = av_find_best_stream(format_context_, AVMEDIA_TYPE_VIDEO, -, -, NULL, );
video_st = format_context_->streams[video_stream_idx]; for (unsigned int i = ; i < format_context_->nb_streams; i++)
{
AVCodecParameters *enc = format_context_->streams[i]->codecpar;
if (!enc)
continue;
if (AVMEDIA_TYPE_VIDEO == enc->codec_type && video_stream_index_ < )
{
width_ = enc->width;
height_ = enc->height; codec_ = avcodec_find_decoder(enc->codec_id);
if (!codec_)
return false;
codec_context_ = avcodec_alloc_context3(codec_);
if (!codec_context_)
return false;
if (avcodec_open2(codec_context_, codec_, NULL) < )
{
avcodec_free_context(&codec_context_);
return false;
} if (width_ && (enc->width != width_))
enc->width = width_; if (height_ && (enc->height != height_)) enc->height = height_; video_stream_index_ = i;
}
}
if (video_stream_index_ == -)
return false; yuv_frame_ = av_frame_alloc();
memset(rgb_data_, , sizeof(uint8_t *) * );
memset(rgb_line_size_, , sizeof(int) * );
rgb_line_size_[] = * width_;
DecodeToImage();
return true;
}
bool FfmpegStreamChr::DecodeToImage(){
if (!format_context_ ||!codec_context_)
return false;
int count_no_video_stream = ;
int continue_counts = ;
const int max_number_of_attempts = ;
// const int max_number_of_video_stream_attempts = 1 << 16;
for (;;)
{
TempImg = cv::Mat();
if (continue_counts > max_number_of_attempts)
return false; // opt_time = GetTickCount();
int ret = av_read_frame(format_context_, &packet_); if (ret == AVERROR(EAGAIN))
{
++continue_counts;
continue;
}
if (ret < )
continue; if (packet_.stream_index != video_stream_index_)
{
// count_no_video_stream++;
//if (count_no_video_stream > max_number_of_video_stream_attempts)
// return false;
av_packet_unref(&packet_);
TempImg.release();
continue;
} // std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now();
ret = avcodec_send_packet(codec_context_, &packet_); if (avcodec_receive_frame(codec_context_, yuv_frame_) == )
{
//std::chrono::system_clock::time_point t2 = std::chrono::system_clock::now();
if (!y2r_sws_context_)
{
y2r_sws_context_ = sws_getContext(width_, height_,
codec_context_->pix_fmt, codec_context_->width, codec_context_->height, /*video_stream_->codec->pix_fmt*/ AV_PIX_FMT_BGR24, /*SWS_BICUBIC*/ SWS_BILINEAR, NULL, NULL, NULL);
if (!y2r_sws_context_)
{
av_packet_unref(&packet_);
TempImg.release();
continue;
}
} if (!TempImg.data)
TempImg.create(height_, width_, CV_8UC3);
rgb_data_[] = TempImg.data; if (sws_scale(y2r_sws_context_, yuv_frame_->data, yuv_frame_->linesize, , codec_context_->height, rgb_data_, rgb_line_size_) <= )
{
av_packet_unref(&packet_);
TempImg.release();
av_frame_unref(yuv_frame_);
return false;
} // std::chrono::system_clock::time_point t3 = std::chrono::system_clock::now();
//printf("decode : %d , switch : %d\n", std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count(), std::chrono::duration_cast<std::chrono::milliseconds>(t3 - t2).count());
if (pts_first)
{
bg_pts = packet_.pts;
pts_first = false;
}
//timestamp = yuv_frame_->pts*av_q2d(video_st->time_base);
// timestamp = (packet_.pts - bg_pts)*av_q2d(video_st->time_base);
// durationstamp = duration; av_packet_unref(&packet_);
av_frame_unref(yuv_frame_);
// return true;
LOG_DEBUG() << "SendToAll \n";
SendToAll(TempImg); } ++continue_counts;
av_packet_unref(&packet_);
} }
解码文件的时候报如下错
Error splitting the input into NAL units
加入如下代码添加到open函数的54行后面,正常解码文件
//TODO:: add to hanldle file
if (avcodec_parameters_to_context(codec_context_, enc) < ){
return false;
}