[英]ffplay cannot play more than one song
我從http://ffmpeg.org/doxygen/trunk/ffplay_8c-source.html獲取了 ffplay.c 文件,並將其重新編輯為 cpp 文件以嵌入到我的 win32 gui 應用程序中。 我對其進行了以下更改。
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;
}
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.