ffpemg使用四:ffmepg復号+Qt表示すなわちプレーヤーの実現

5736 ワード

前編では録画画面データのプッシュストリームを実現しましたが、今はプレーヤーとしてプッシュストリームのデータを再生します.同様にこの記事では、ストリーミングメディアサーバの構築については説明しません(別途説明します).
コードは非常に簡単で、受信データの復号を完了するだけでよい.これらは第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); }