2016-03-16 93 views
0

我開發Qt應用程序,它可以使用波紋管代碼播放多個視頻文件。使Qt Player編解碼器獨立

QMediaPlayer *player; 
QString fileName = "C:/username/test.h264"; 
player->setmedia(QUrl::fromLocalFile(fileName)); 

在起點,我不能播放所有類型的視頻文件,所以我在我的系統,現在當我的球員開始編解碼器啓動,並在高我的CPU使用率達到上安裝解碼器。(顯示波紋圖像)

enter image description here

它見證了外部解碼器

可以在上圖中右側底角LAW(紅色標籤)見開始。

現在,我要讓我的Qt播放器的編解碼獨立,意味着我知道我的球員都只能玩.h264文件,所以我將只使用H264解碼器,無需音頻的,所以我不會用音頻解碼器。

據我所知,QMediaPlayer開始解碼器,當它出現在圖片中,糾正我,如果我錯了。那麼,我能做些什麼來阻止外部解碼器和內部解碼幀併成功播放?

編輯:代碼用於使用的FFmpeg

FFmpegAudio.pro

TARGET = fooAudioFFMPEG 
QT  += core gui qml quick widgets 
TEMPLATE = app 
SOURCES += main.cpp \ 
    mainwindow.cpp 
HEADERS += mainwindow.h \ 
    wrapper.h 
FORMS += mainwindow.ui 
QMAKE_CXXFLAGS += -D__STDC_CONSTANT_MACROS 

LIBS += -pthread 
LIBS += -L/usr/local/lib 
LIBS += -lavdevice 
LIBS += -lavfilter 
LIBS += -lpostproc 
LIBS += -lavformat 
LIBS += -lavcodec 
LIBS += -ldl 
LIBS += -lXfixes 
LIBS += -lXext 
LIBS += -lX11 
LIBS += -lasound 
LIBS += -lSDL 
LIBS += -lx264 
LIBS += -lvpx 
LIBS += -lvorbisenc 
LIBS += -lvorbis 
LIBS += -logg 
LIBS += -lopencore-amrwb 
LIBS += -lopencore-amrnb 
LIBS += -lmp3lame 
LIBS += -lfaac 
LIBS += -lz 
LIBS += -lrt 
LIBS += -lswscale 
LIBS += -lavutil 
LIBS += -lm 

mainwindow.h音頻解碼

#ifndef MAINWINDOW_H 
#define MAINWINDOW_H 

#include <QMainWindow> 

namespace Ui { 
    class MainWindow; 
} 

class MainWindow : public QMainWindow { 
    Q_OBJECT 
public: 
    MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 

protected: 
    void changeEvent(QEvent *e); 

private: 
    Ui::MainWindow *ui; 

private slots: 
    void on_pushButton_clicked(); 
}; 

#endif // MAINWINDOW_H 

wrapper.h

#ifndef WRAPPER_H_ 
#define WRAPPER_H_ 

#include <math.h> 

#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> 

#define INBUF_SIZE 4096 
#define AUDIO_INBUF_SIZE 20480 
#define AUDIO_REFILL_THRESH 4096 



/* check that a given sample format is supported by the encoder */ 
static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt) 
{ 
    const enum AVSampleFormat *p = codec->sample_fmts; 

    while (*p != AV_SAMPLE_FMT_NONE) { 
     if (*p == sample_fmt) 
      return 1; 
     p++; 
    } 
    return 0; 
} 

/* just pick the highest supported samplerate */ 
static int select_sample_rate(AVCodec *codec) 
{ 
    const int *p; 
    int best_samplerate = 0; 

    if (!codec->supported_samplerates) 
     return 44100; 

    p = codec->supported_samplerates; 
    while (*p) { 
     best_samplerate = FFMAX(*p, best_samplerate); 
     p++; 
    } 
    return best_samplerate; 
} 

/* select layout with the highest channel count */ 
static int select_channel_layout(AVCodec *codec) 
{ 
    const uint64_t *p; 
    uint64_t best_ch_layout = 0; 
    int best_nb_channells = 0; 

    if (!codec->channel_layouts) 
     return AV_CH_LAYOUT_STEREO; 

    p = codec->channel_layouts; 
    while (*p) { 
     int nb_channels = av_get_channel_layout_nb_channels(*p); 

     if (nb_channels > best_nb_channells) { 
      best_ch_layout = *p; 
      best_nb_channells = nb_channels; 
     } 
     p++; 
    } 
    return best_ch_layout; 
} 

/* 
* Audio encoding example 
*/ 
static void audio_encode_example(const char *filename) 
{ 
    AVCodec *codec; 
    AVCodecContext *c= NULL; 
    AVFrame *frame; 
    AVPacket pkt; 
    int i, j, k, ret, got_output; 
    int buffer_size; 
    FILE *f; 
    uint16_t *samples; 
    float t, tincr; 

    printf("Encode audio file %s\n", filename); 

    /* find the MP2 encoder */ 
    codec = avcodec_find_encoder(AV_CODEC_ID_MP2); 
    if (!codec) { 
     fprintf(stderr, "Codec not found\n"); 
     exit(1); 
    } 

    c = avcodec_alloc_context3(codec); 
    if (!c) { 
     fprintf(stderr, "Could not allocate audio codec context\n"); 
     exit(1); 
    } 

    /* put sample parameters */ 
    c->bit_rate = 64000; 

    /* check that the encoder supports s16 pcm input */ 
    c->sample_fmt = AV_SAMPLE_FMT_S16; 
    if (!check_sample_fmt(codec, c->sample_fmt)) { 
     fprintf(stderr, "Encoder does not support sample format %s", 
       av_get_sample_fmt_name(c->sample_fmt)); 
     exit(1); 
    } 

    /* select other audio parameters supported by the encoder */ 
    c->sample_rate = select_sample_rate(codec); 
    c->channel_layout = select_channel_layout(codec); 
    c->channels  = av_get_channel_layout_nb_channels(c->channel_layout); 

    /* open it */ 
    if (avcodec_open2(c, codec, NULL) < 0) { 
     fprintf(stderr, "Could not open codec\n"); 
     exit(1); 
    } 

    f = fopen(filename, "wb"); 
    if (!f) { 
     fprintf(stderr, "Could not open %s\n", filename); 
     exit(1); 
    } 

    /* frame containing input raw audio */ 
    frame = avcodec_alloc_frame(); 
    if (!frame) { 
     fprintf(stderr, "Could not allocate audio frame\n"); 
     exit(1); 
    } 

    frame->nb_samples  = c->frame_size; 
    frame->format   = c->sample_fmt; 
    frame->channel_layout = c->channel_layout; 

    /* the codec gives us the frame size, in samples, 
    * we calculate the size of the samples buffer in bytes */ 
    buffer_size = av_samples_get_buffer_size(NULL, c->channels, c->frame_size, 
              c->sample_fmt, 0); 
    samples = (uint16_t *)av_malloc(buffer_size); 
    if (!samples) { 
     fprintf(stderr, "Could not allocate %d bytes for samples buffer\n", 
       buffer_size); 
     exit(1); 
    } 
    /* setup the data pointers in the AVFrame */ 
    ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, 
            (const uint8_t*)samples, buffer_size, 0); 
    if (ret < 0) { 
     fprintf(stderr, "Could not setup audio frame\n"); 
     exit(1); 
    } 

    /* encode a single tone sound */ 
    t = 0; 
    tincr = 2 * M_PI * 440.0/c->sample_rate; 
    for(i=0;i<200;i++) { 
     av_init_packet(&pkt); 
     pkt.data = NULL; // packet data will be allocated by the encoder 
     pkt.size = 0; 

     for (j = 0; j < c->frame_size; j++) { 
      samples[2*j] = (int)(sin(t) * 10000); 

      for (k = 1; k < c->channels; k++) 
       samples[2*j + k] = samples[2*j]; 
      t += tincr; 
     } 
     /* encode the samples */ 
     ret = avcodec_encode_audio2(c, &pkt, frame, &got_output); 
     if (ret < 0) { 
      fprintf(stderr, "Error encoding audio frame\n"); 
      exit(1); 
     } 
     if (got_output) { 
      fwrite(pkt.data, 1, pkt.size, f); 
      av_free_packet(&pkt); 
     } 
    } 

    /* get the delayed frames */ 
    for (got_output = 1; got_output; i++) { 
     ret = avcodec_encode_audio2(c, &pkt, NULL, &got_output); 
     if (ret < 0) { 
      fprintf(stderr, "Error encoding frame\n"); 
      exit(1); 
     } 

     if (got_output) { 
      fwrite(pkt.data, 1, pkt.size, f); 
      av_free_packet(&pkt); 
     } 
    } 
    fclose(f); 

    av_freep(&samples); 
    avcodec_free_frame(&frame); 
    avcodec_close(c); 
    av_free(c); 
} 

/* 
* Audio decoding. 
*/ 
static void audio_decode_example(const char *outfilename, const char *filename) 
{ 
    AVCodec *codec; 
    AVCodecContext *c= NULL; 
    int len; 
    FILE *f, *outfile; 
    uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; 
    AVPacket avpkt; 
    AVFrame *decoded_frame = NULL; 

    av_init_packet(&avpkt); 

    printf("Decode audio file %s to %s\n", filename, outfilename); 

    /* find the mpeg audio decoder */ 
    codec = avcodec_find_decoder(AV_CODEC_ID_MP2); 
    if (!codec) { 
     fprintf(stderr, "Codec not found\n"); 
     exit(1); 
    } 

    c = avcodec_alloc_context3(codec); 
    if (!c) { 
     fprintf(stderr, "Could not allocate audio codec context\n"); 
     exit(1); 
    } 

    /* open it */ 
    if (avcodec_open2(c, codec, NULL) < 0) { 
     fprintf(stderr, "Could not open codec\n"); 
     exit(1); 
    } 

    f = fopen(filename, "rb"); 
    if (!f) { 
     fprintf(stderr, "Could not open %s\n", filename); 
     exit(1); 
    } 
    outfile = fopen(outfilename, "wb"); 
    if (!outfile) { 
     av_free(c); 
     exit(1); 
    } 

    /* decode until eof */ 
    avpkt.data = inbuf; 
    avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f); 

    while (avpkt.size > 0) { 
     int got_frame = 0; 

     if (!decoded_frame) { 
      if (!(decoded_frame = avcodec_alloc_frame())) { 
       fprintf(stderr, "Could not allocate audio frame\n"); 
       exit(1); 
      } 
     } else 
      avcodec_get_frame_defaults(decoded_frame); 

     len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt); 
     if (len < 0) { 
      fprintf(stderr, "Error while decoding\n"); 
      exit(1); 
     } 
     if (got_frame) { 
      /* if a frame has been decoded, output it */ 
      int data_size = av_samples_get_buffer_size(NULL, c->channels, 
                 decoded_frame->nb_samples, 
                 c->sample_fmt, 1); 
      fwrite(decoded_frame->data[0], 1, data_size, outfile); 
     } 
     avpkt.size -= len; 
     avpkt.data += len; 
     avpkt.dts = 
     avpkt.pts = AV_NOPTS_VALUE; 
     if (avpkt.size < AUDIO_REFILL_THRESH) { 
      /* Refill the input buffer, to avoid trying to decode 
      * incomplete frames. Instead of this, one could also use 
      * a parser, or use a proper container format through 
      * libavformat. */ 
      memmove(inbuf, avpkt.data, avpkt.size); 
      avpkt.data = inbuf; 
      len = fread(avpkt.data + avpkt.size, 1, 
         AUDIO_INBUF_SIZE - avpkt.size, f); 
      if (len > 0) 
       avpkt.size += len; 
     } 
    } 

    fclose(outfile); 
    fclose(f); 

    avcodec_close(c); 
    av_free(c); 
    avcodec_free_frame(&decoded_frame); 
} 

/* 
* Main WRAPPER function 
*/ 
void service(){ 


    /* register all the codecs */ 
    avcodec_register_all(); 


    audio_encode_example("test.mp2"); 
    audio_decode_example("test.sw", "test.mp2"); 

} 

#endif 

的main.cpp

​​

mainwindow.cpp

#include "mainwindow.h" 
#include "ui_mainwindow.h" 

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 
} 

MainWindow::~MainWindow() 
{ 
    delete ui; 
} 

void MainWindow::changeEvent(QEvent *e) 
{ 
    QMainWindow::changeEvent(e); 
    switch (e->type()) { 
    case QEvent::LanguageChange: 
     ui->retranslateUi(this); 
     break; 
    default: 
     break; 
    } 
} 

void MainWindow::on_pushButton_clicked() 
{ 
     this->close(); 
} 

mainwindow.ui //什麼都不重要

感謝。

回答

1

Qt的內置媒體播放器使用系統編解碼器。如果你想顛覆這一點,你需要使用別的東西。

我還沒有使用它,但有提到QtAV,它使用FFmpeg。

QtAV網站觀察到:QtMultimedia的實施依賴於平臺。它在Windows上使用dshow,在Linux上使用gstream等。可能不是一件容易的工作來支持一個新的平臺。

+0

感謝信息,我知道QtAV是Qt和FFmpeg的,但相結合的很好的例子,它很難理解,我想要一些簡單的解決方案,以發揮框架在我的球員。我有一個使用FFmpeg包裝解碼音頻的例子,我會在我的問題區域添加一些代碼部分。 –

0

只是爲了播放視頻文件Qt中,你也可以使用libvlc,著名的媒體播放器後(http://www.videolan.org

初始化:

libvlc_instance_t *vlcinstance = libvlc_new(0, NULL); 
libvlc_media_player_t *player = libvlc_media_player_new(vlcinstance); 
libvlc_media_t *media = libvlc_media_new_path(vlcinstance, file_path); 

使用一些Qt物件顯示視頻:

libvlc_media_player_set_drawable(player, some_widget->winId()); 

播放視頻:

libvlc_media_player_set_media(player, media); 
libvlc_media_player_play(player); 

這個示例代碼當然省略了錯誤檢查。

請參考以下鏈接一個更完整的例子:https://wiki.videolan.org/LibVLC_SampleCode_Qt

+0

謝謝@Philipp Ludwig,我認爲這個應用程序也會依賴於平臺,如果我沒有錯,最終vlc的意思就是使用OS編解碼器。我想完全平臺獨立,就像上面的例子音頻文件的編碼和解碼一樣,使用FFmpeg wrapper,dos't mater是OS和編碼器。 –

+1

@TejasVirpariya VLC庫附帶了自己的編解碼器集合,因此它可以播放各種格式而不需要任何操作系統安裝的視頻編解碼器。 –

+0

謝謝@Philipp Ludwig,我會檢查CPU性能,如果它會設定我的目標,我一定會使用LibVLC。再次感謝。 –