簡體   English   中英

ffplay 不能播放多於一首歌

[英]ffplay cannot play more than one song

我從http://ffmpeg.org/doxygen/trunk/ffplay_8c-source.html獲取了 ffplay.c 文件,並將其重新編輯為 cpp 文件以嵌入到我的 win32 gui 應用程序中。 我對其進行了以下更改。

  1. 將 int main 函數變成本地函數如下,我可以通過 HWND 來嵌入播放器
void Ffplay::play_song(string file, HWND parent, bool* successfull)
{
    int flags;
    VideoState* is;
    input_filename = file; 
    /* register all codecs, demux and protocols */
#if CONFIG_AVDEVICE
    avdevice_register_all();
#endif
    //avformat_network_init();
    //check whether the filename is valid
    if (input_filename.empty())
    {
        logger.log(logger.LEVEL_ERROR, "filename %s is not valid\n", file);
        return;
    }
    if (display_disable)
    {
        video_disable = 1;
    }
    flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
    if (audio_disable)
        flags &= ~SDL_INIT_AUDIO;
    else
    {
        /* Try to work around an occasional ALSA buffer underflow issue when the
         * period size is NPOT due to ALSA resampling by forcing the buffer size. */
        if (!SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE"))
            SDL_setenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE", "1", 1);
    }
    if (display_disable)
        flags &= ~SDL_INIT_VIDEO;
    SDL_SetMainReady();
    if (SDL_Init(flags))
    {
        logger.log(logger.LEVEL_ERROR, "Could not initialize SDL - %s\n", SDL_GetError());
        logger.log(logger.LEVEL_ERROR, "(Did you set the DISPLAY variable?)\n");
        return;
    }
    //Initialize optional fields of a packet with default values.
    //Note, this does not touch the data and size members, which have to be initialized separately.
    av_init_packet(&flush_pkt);
    flush_pkt.data = (uint8_t*)&flush_pkt;

    if (!display_disable)
    {
        int flags = SDL_WINDOW_HIDDEN;
        if (alwaysontop)
#if SDL_VERSION_ATLEAST(2,0,5)
            flags |= SDL_WINDOW_ALWAYS_ON_TOP;
#else
            logger.log(logger.LEVEL_INFO, "SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n");
#endif
        if (borderless)
            flags |= SDL_WINDOW_BORDERLESS;
        else
            flags |= SDL_WINDOW_RESIZABLE;
        SDL_InitSubSystem(flags);
        ShowWindow(parent, true);
        //window = SDL_CreateWindow(program_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, default_width, default_height, flags);
        window = SDL_CreateWindowFrom(parent);
        SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
        if (window) {
            renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
            if (!renderer)
            {
                logger.log(logger.LEVEL_ERROR, "Failed to initialize a hardware accelerated renderer: %s\n", SDL_GetError());
                renderer = SDL_CreateRenderer(window, -1, 0);
            }
            if (renderer)
            {
                if (!SDL_GetRendererInfo(renderer, &renderer_info))
                {
                    logger.log(logger.LEVEL_INFO, "Initialized %s renderer.\n", renderer_info.name);
                }
            }
        }
        if (!window || !renderer || !renderer_info.num_texture_formats)
        {
            logger.log(logger.LEVEL_ERROR, "Failed to create window or renderer: %s\n", SDL_GetError());
            return;
        }
    }

    is = stream_open(input_filename.c_str(), file_iformat);
    if (!is)
    {
        logger.log(logger.LEVEL_ERROR, "Failed to initialize VideoState!\n");
        return;
    }
    //the song is playing now
    *successfull = true;
    event_loop(is);
    //the song has quit;
    *successfull = false;
}
  1. 更改了回調函數,因為 c++ 無法使用靜態函數,例如,
void Ffplay::static_sdl_audio_callback(void* opaque, Uint8* stream, int len)
{
    static_cast<Ffplay*>(opaque)->sdl_audio_callback(opaque, stream, len);
}

關閉不會從主文件更改為關閉音頻和 sdl 框架

void Ffplay::do_exit(VideoState* is)
{
    abort = true;
    if(is)
    {
        stream_close(is);
    }
    if (renderer)
        SDL_DestroyRenderer(renderer);
    if (window)
         SDL_DestroyWindow(window);
#if CONFIG_AVFILTER
    av_freep(&vfilters_list);
#endif
    avformat_network_deinit();
    SDL_Quit();

}

我從主 gui 調用函數如下

ft=std::async(launch::async, &Menu::play_song, this, songs_to_play.at(0));

menu::play_song函數是:

void Menu::play_song(wstring song_path)
{
    ready_to_play_song = false;
    OutputDebugString(L"\nbefore song\n");
    using std::future;
    using std::async;
    using std::launch;

    string input{ song_path.begin(),song_path.end() };
    Ffplay ffplay;
    ffplay.play_song(input, h_sdl_window, &song_opened);

    OutputDebugString(L"\nafter song\n");
    ready_to_play_song = true;
}

問題是我只能播放一首歌。 如果我再次調用menu::play_song函數,聲音就會丟失,視頻/藝術封面偶爾也會丟失。 似乎有些資源沒有被釋放或類似的東西。

我已將問題本地化到此功能

int Ffplay::packet_queue_get(PacketQueue* q, AVPacket* pkt, int block, int* serial)
{

    MyAVPacketList* pkt1;
    int ret;
    int count=0;
    SDL_LockMutex(q->mutex);

    for (;;) 
    {


        if (q->abort_request)
        {
            ret = -1;
            break;
        }

        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
            q->duration -= pkt1->pkt.duration;
            *pkt = pkt1->pkt;
            if (serial)
                *serial = pkt1->serial;
            av_free(pkt1);
            ret = 1;
            break;
        }
        else if (!block) {
            ret = 0;
            break;
        }
        else 
        {
            logger.log(logger.LEVEL_INFO, "packet_queue before");
            SDL_CondWait(q->cond, q->mutex);
            logger.log(logger.LEVEL_INFO, "packet_queue after");

        }
    }
    SDL_UnlockMutex(q->mutex);
    return ret;
}

調用SDL_CondWait(q->cond, q->mutex); 一去不復返

首先,抱歉,這個問題有點含糊,因為我無法上傳大部分代碼,因為它很長,這就是為什么我將鏈接發布到與我的相似的原始代碼,唯一的區別是我已將函數從 C 靜態更改到 C++ 公共的。

問題是變量SDL_AudioDeviceID audio_dev

使用audio_dev = SDL_OpenAudioDevice(NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE)分配變量沒有按計划分配變量,並且在使用SDL_CloseAudioDevice(audio_dev);關閉音頻設備時SDL_CloseAudioDevice(audio_dev); 音頻設備變量為 0,因此設備未關閉,因此第二首歌曲缺少聲音或視頻可能掛起。 這是使用各種線程調用本地回調函數的結果,這些回調函數按照 SDL api 的預期轉換為靜態性質。

答案是將設備變量更改為靜態變量,即static SDL_AudioDeviceID audio_dev; 因此可以從程序中的任何位置訪問該變量

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM