2012年10月28日 星期日

FFmpeg tutorial practice - tutorial03

能夠把Video顯示在螢幕上之後,接著繼續加入Audio,也就是 Tutorial03 的目的。(如果還沒試過 Tutorial01,請先從 FFmpeg tutorial practice - tutorial01 開始練習) 播放Audio,一樣是借用SDL(Simple DirectMedia Layer),讓你能聽到聲音。主要的概念是從檔案中讀取 Audio stream 之後,把每一個 Audio 的 Packet 掫取出來 decode,把 decode 完成的資料傳給 SDL 去做播放的動作。其中,要注意 Audio 格式能不能被 decode,也就是你使用的 FFmpeg 的 libraries 是否支援你所要用的格式,如果不支援,那一定聽不到正確的聲音的。


事實上,在 Audio 上花了不少時間,主要是因為測試用的檔案,Video 和 Audio 有不同的格式,我只是想先用最單純的方法來實作這個練習,所以使用的是 Video (H.264) + Audio (AAC) 的測試檔,但是在網路上下載的不一定就剛好是這樣的組合,格式一不對,很容易就會出現問題,所以一定要小心格式的問題。另外,也可以參考 ffplay.c 這個檔案,雖然複雜了點,但先找到你想知道的部份,還是可以把範圍縮小。

加入 Audio 我認為最主要的部份就是怎麼去解碼 Audio frame ,以下就列出修改後的程式:


for(;;) {

    while(avpkt.size > 0) {
        if (!decoded_frame) {
            if (!(decoded_frame = avcodec_alloc_frame()))
                return AVERROR(ENOMEM);
        } else
            avcodec_get_frame_defaults(decoded_frame);
        len = avcodec_decode_audio4(aCodecCtx, decoded_frame, &got_frame, &avpkt);

        if(len < 0) {
            /* if error, skip frame */
            avpkt.size = 0;
            break;
        }

        avpkt.data += len;
        avpkt.size -= len;

        if (!got_frame) {
            continue;
        }

        data_size = av_samples_get_buffer_size(NULL, aCodecCtx->channels, decoded_frame->nb_samples, aCodecCtx->sample_fmt, 1);
        memmove(audio_buf, decoded_frame->data[0], data_size);

        /* We have data, return it and come back for more later */
        return data_size;
    }

    if(quit) {
        return -1;
    }

    if(packet_queue_get(&audioq, &avpkt, 1) < 0) {
        return -1;
    }
}

在這裡還想說一件事,那就是有觀念程式才知道怎麼寫。有時候你看不懂某一段程式,一定是有什麼觀念你還不知道,你才會看不懂。

沒有留言:

張貼留言