ffpemg使用四:ffmepg復号+Qt表示すなわちプレーヤーの実現
5736 ワード
前編では録画画面データのプッシュストリームを実現しましたが、今はプレーヤーとしてプッシュストリームのデータを再生します.同様にこの記事では、ストリーミングメディアサーバの構築については説明しません(別途説明します).
コードは非常に簡単で、受信データの復号を完了するだけでよい.これらは第1編で紹介されたが、唯一注意したのは、Qtがyuvフォーマットをサポートしていないことであり、復号したyuvをrgbに変換する必要があることである.変換の具体的な原理はもう言わないで、とても簡単で、ただ行列の演算をしますが、乗算で、cupは乗除法の効率を処理するのがきわめて低いため、ffmpegの変換関数sws_を使うことを推薦しますscale()は、マルチメディアの最適化命令があり、効率が高い.
構想:スレッドで受信したネットワークデータを復号し、メインスレッドに送信し、メインスレッドは1枚の画像の展示を行う.(個人的にはこの再生方式は効率的ではないと思いますが、ストリーミングメディアに流れるときはflv形式になっているはずですが、QtのPhonenフレームワークで再生できるとしたら、まだ検証されていませんが、現在はこの方法で実現しています)
上のコード:
コードは非常に簡単で、受信データの復号を完了するだけでよい.これらは第1編で紹介されたが、唯一注意したのは、Qtがyuvフォーマットをサポートしていないことであり、復号したyuvをrgbに変換する必要があることである.変換の具体的な原理はもう言わないで、とても簡単で、ただ行列の演算をしますが、乗算で、cupは乗除法の効率を処理するのがきわめて低いため、ffmpegの変換関数sws_を使うことを推薦しますscale()は、マルチメディアの最適化命令があり、効率が高い.
構想:スレッドで受信したネットワークデータを復号し、メインスレッドに送信し、メインスレッドは1枚の画像の展示を行う.(個人的にはこの再生方式は効率的ではないと思いますが、ストリーミングメディアに流れるときはflv形式になっているはずですが、QtのPhonenフレームワークで再生できるとしたら、まだ検証されていませんが、現在はこの方法で実現しています)
上のコード:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
// , ffmpeg
void MainWindow::on_pushButton_clicked()
{
connect(&mythread,&ffmpegThread::sendImage ,this,&MainWindow::showImage);
mythread.start();
}
// , ffmpeg
void MainWindow::showImage(QImage image)
{
pix=QPixmap::fromImage(image.scaled(image.width(),image.height()));
update();
}
//
void MainWindow::paintEvent(QPaintEvent *e)
{
ui->label->setPixmap(pix);
}#include "ffmpegthread.h"
#include
extern "C"
{
#include
#include
#include
#include
#include
#include
#include
}
ffmpegThread::ffmpegThread()
{
}
// 《ffempeg 》 ; url, yuv420p rgb, Qt yuv
void ffmpegThread::run()
{
AVFormatContext *pFormatCtx;
int i, videoindex;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();
avdevice_register_all();
char filepath[]="rtmp://192.168.80.31:8811/myapp/test5";
if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){
printf("Couldn't open input stream.
");
}
if(avformat_find_stream_info(pFormatCtx,NULL)<0)
{
printf("Couldn't find stream information.
");
}
videoindex=-1;
for(i=0; inb_streams; i++)
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoindex=i;
break;
}
if(videoindex==-1)
{
printf("Didn't find a video stream.
");
}
pCodecCtx=pFormatCtx->streams[videoindex]->codec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
printf("Codec not found.
");
}
if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
{
printf("Could not open codec.
");
}
AVFrame *pFrame,*pFrameYUV,*pFrameRGB;
pFrame=av_frame_alloc();
pFrameYUV=av_frame_alloc();
pFrameRGB=av_frame_alloc();
unsigned char *out_buffer=(unsigned char *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
unsigned char *rgbBuffer=(unsigned char *)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height));
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);// pFrameRGB buffer。 buffer
//
int ret, got_picture;
AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));
#if OUTPUT_YUV420P
FILE *fp_yuv=fopen("output.yuv","wb+");
#endif
struct SwsContext *img_convert_ctx,*img_convert_ctx_rgb;
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
//
avpicture_fill((AVPicture *)pFrameRGB,rgbBuffer,AV_PIX_FMT_RGB32,pCodecCtx->width, pCodecCtx->height);
img_convert_ctx_rgb=sws_getContext(pCodecCtx->width,pCodecCtx->height,AV_PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,AV_PIX_FMT_RGB32,SWS_BICUBIC, NULL, NULL, NULL);
for (;;) {
if(av_read_frame(pFormatCtx, packet)>=0)
{
if(packet->stream_index==videoindex)
{
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);// packet pFrame,pFrame->data = packet->data? pFrame->linesize=packet->linesize
if(ret < 0){
printf("Decode Error.
");
}
if(got_picture)
{
sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
if(img_convert_ctx_rgb != NULL)
{
// rgb32
sws_scale(img_convert_ctx_rgb,pFrameYUV->data,pFrameYUV->linesize,0,pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize);
// QImage,
QImage image((uchar *)pFrameRGB->data[0],pCodecCtx->width, pCodecCtx->height,QImage::Format_ARGB32);
emit sendImage(image);
}
}
}
av_free_packet(packet);
}
}
if(img_convert_ctx)
sws_freeContext(img_convert_ctx);
if(img_convert_ctx_rgb)
sws_freeContext(img_convert_ctx_rgb);
av_free(rgbBuffer);
av_free(out_buffer);
av_free(pFrame);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
}