//指定文件的编码为UTF-8 #pragma execution_character_set("utf-8") #include "ReverseDecodThread.h" ReverseDecodThread::ReverseDecodThread() { qDebug() << "FFMPEG版本信息:" << av_version_info(); } ReverseDecodThread::~ReverseDecodThread() { } /* 功能: 设置媒体文件 */ int ReverseDecodThread::set_VideoFile(QString media) { //打开媒体文件 QByteArray array=media.toUtf8(); strncpy(m_MediaFile, array.data(), sizeof(m_MediaFile)); m_run = 1; return 1; } void ReverseDecodThread::SetSate(int run) { m_run = run; } int ReverseDecodThread::GetSate() { return m_run; } //跳转视频帧 void ReverseDecodThread::SetSeekPos(qint64 pos) { is_CurrentSeekPos = 1; m_n64CurrentSeekPos = pos; m_run=1; //运行状态 //获取系统本地时间 play_base_time=QDateTime::currentMSecsSinceEpoch(); } void ReverseDecodThread::PausePlay() { m_run = 2; } void ReverseDecodThread::StopPlay() { m_run = 0; } void ReverseDecodThread::LogSend(QString text) { //qDebug() << text; } //线程执行起点 void ReverseDecodThread::run() { LogSend("开始播放视频.\n"); StartPlay(); } //播放视频 int ReverseDecodThread::StartPlay() { format_ctx = avformat_alloc_context(); if (!format_ctx) { LogSend(tr("初始化失败 无法打开视频文件: %1").arg(m_MediaFile)); return -1; } //1.打开多媒体流,并且获取一些信息 if(avformat_open_input(&format_ctx, m_MediaFile, nullptr, nullptr) != 0) { LogSend(tr("无法打开视频文件: %1").arg(m_MediaFile)); return -1; } //2. 读取媒体文件的数据包以获取流信息 if(avformat_find_stream_info(format_ctx, nullptr) < 0) { LogSend(tr("无法获取流信息.\n")); return -1; } // context = avcodec_alloc_context3(codec) AVCodecContext* avctx = avcodec_alloc_context3(NULL); if (nullptr == avctx) { return -1; } st_index[AVMEDIA_TYPE_VIDEO] = av_find_best_stream(format_ctx, AVMEDIA_TYPE_VIDEO, st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0); st_index[AVMEDIA_TYPE_AUDIO] = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, st_index[AVMEDIA_TYPE_AUDIO], st_index[AVMEDIA_TYPE_VIDEO], NULL, 0); //3.打印视频的信息 LogSend(tr("视频中流的数量: %1\n").arg(format_ctx->nb_streams)); for(int i = 0; i < format_ctx->nb_streams; ++i) { const AVStream* stream = format_ctx->streams[i]; if(stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { int ret = avcodec_parameters_to_context(avctx, stream->codecpar); if (ret < 0) { return -1; } //查找解码器 const AVCodec *video_pCodec=avcodec_find_decoder(avctx->codec_id); //打开解码器 if(avcodec_open2(avctx, video_pCodec,nullptr)!=0) { LogSend(tr("解码器打开失败.\n")); return -1; } video_stream_index = i; bool flag = false; if (video_width != stream->codecpar->width) { video_width = stream->codecpar->width; flag = true; } if (video_height != stream->codecpar->height) { video_height = stream->codecpar->height; flag = true; } if (flag) { emit VideoSizeChanged(video_width, video_height); } LogSend(tr("视频帧的尺寸(以像素为单位): (宽X高)%1x%2 像素格式: %3\n").arg( stream->codecpar->width).arg(stream->codecpar->height).arg(stream->codecpar->format)); } } if (video_stream_index == -1) { LogSend("没有检测到视频流.\n"); return -1; } AVRational frameRate = format_ctx->streams[video_stream_index]->avg_frame_rate; /*设置视频转码器*/ SRC_VIDEO_pFrame = av_frame_alloc(); RGB24_pFrame = av_frame_alloc();// 存放解码后YUV数据的缓冲区 //将解码后的YUV数据转换成RGB24 img_convert_ctx = sws_getContext(video_width, video_height, avctx->pix_fmt,video_width, video_height, AV_PIX_FMT_RGBA, SWS_BICUBIC, nullptr, nullptr, nullptr); //计算RGB图像所占字节大小 int numBytes= av_image_get_buffer_size(AV_PIX_FMT_RGBA,video_width,video_height, 1); //申请空间存放RGB图像数据 out_buffer_rgb = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t)); // avpicture_fill函数将ptr指向的数据填充到picture内,但并没有拷贝,只是将picture结构内的data指针指向了ptr的数据 /*avpicture_fill((AVPicture *) RGB24_pFrame, out_buffer_rgb, AV_PIX_FMT_RGB24, video_width, video_height);*/ av_image_fill_arrays(RGB24_pFrame->data, RGB24_pFrame->linesize, out_buffer_rgb, AV_PIX_FMT_RGBA, video_width, video_height, 1); qDebug()<<"format_ctx->duration:"<duration; //获取系统本地时间 play_base_time=QDateTime::currentMSecsSinceEpoch(); // m_run = 1; //表示视频加载成功 while(m_run) { if(m_run == 2) { msleep(100); //暂停播放 continue; } if (is_CurrentSeekPos) { is_CurrentSeekPos = 0; //偏移到指定位置再开始解码 AVSEEK_FLAG_BACKWARD 向后找最近的关键帧 av_seek_frame(format_ctx, -1, m_n64CurrentSeekPos* AV_TIME_BASE, AVSEEK_FLAG_BACKWARD); qDebug()<<"跳转的位置:"<streams[video_stream_index]->time_base) * pkt.pts; // qDebug()<<"pkt.pts:"<data, SRC_VIDEO_pFrame->linesize, 0, video_height, RGB24_pFrame->data, RGB24_pFrame->linesize); //5. 加载图片数据 QImage image(out_buffer_rgb,video_width,video_height,QImage::Format_RGBA8888); //通知界面更新 VideoDataOutput(image.copy()); //时间信号 sig_getCurrentTime(video_clock, format_ctx->duration *1.0 / AV_TIME_BASE); QThread::msleep(40); } //释放包 av_packet_unref(&pkt); } LogSend("视频音频解码播放器的线程退出成功.\n"); if(SRC_VIDEO_pFrame) av_frame_free(&SRC_VIDEO_pFrame); if(RGB24_pFrame) av_frame_free(&RGB24_pFrame); if(img_convert_ctx)sws_freeContext(img_convert_ctx); if(out_buffer_rgb)av_free(out_buffer_rgb); SRC_VIDEO_pFrame=nullptr; RGB24_pFrame=nullptr; img_convert_ctx=nullptr; out_buffer_rgb=nullptr; if(format_ctx) { avcodec_free_context(&avctx); avformat_close_input(&format_ctx);//释放解封装器的空间,以防空间被快速消耗完 avformat_free_context(format_ctx); } return 0; }