static void ffmpeg_flush_buffers(ffmpeg_t *handle) { bool did_work; void *video_buf = av_malloc(2 * handle->params.fb_width * handle->params.fb_height * handle->video.pix_size); size_t audio_buf_size = handle->config.audio_enable ? (handle->audio.codec->frame_size * handle->params.channels * sizeof(int16_t)) : 0; void *audio_buf = NULL; if (audio_buf_size) audio_buf = av_malloc(audio_buf_size); /* Try pushing data in an interleaving pattern to * ease the work of the muxer a bit. */ do { struct ffemu_video_data attr_buf; did_work = false; if (handle->config.audio_enable) { if (fifo_read_avail(handle->audio_fifo) >= audio_buf_size) { struct ffemu_audio_data aud = {0}; fifo_read(handle->audio_fifo, audio_buf, audio_buf_size); aud.frames = handle->audio.codec->frame_size; aud.data = audio_buf; ffmpeg_push_audio_thread(handle, &aud, true); did_work = true; } } if (fifo_read_avail(handle->attr_fifo) >= sizeof(attr_buf)) { fifo_read(handle->attr_fifo, &attr_buf, sizeof(attr_buf)); fifo_read(handle->video_fifo, video_buf, attr_buf.height * attr_buf.pitch); attr_buf.data = video_buf; ffmpeg_push_video_thread(handle, &attr_buf); did_work = true; } } while (did_work); /* Flush out last audio. */ if (handle->config.audio_enable) ffmpeg_flush_audio(handle, audio_buf, audio_buf_size); /* Flush out last video. */ ffmpeg_flush_video(handle); av_free(video_buf); av_free(audio_buf); }
static void ffmpeg_thread(void *data) { ffmpeg_t *ff = (ffmpeg_t*)data; // For some reason, FFmpeg has a tendency to crash if we don't overallocate a bit. :s void *video_buf = av_malloc(2 * ff->params.fb_width * ff->params.fb_height * ff->video.pix_size); assert(video_buf); size_t audio_buf_size = ff->config.audio_enable ? (ff->audio.codec->frame_size * ff->params.channels * sizeof(int16_t)) : 0; void *audio_buf = audio_buf_size ? av_malloc(audio_buf_size) : NULL; while (ff->alive) { struct ffemu_video_data attr_buf; bool avail_video = false; bool avail_audio = false; slock_lock(ff->lock); if (fifo_read_avail(ff->attr_fifo) >= sizeof(attr_buf)) avail_video = true; if (ff->config.audio_enable) if (fifo_read_avail(ff->audio_fifo) >= audio_buf_size) avail_audio = true; slock_unlock(ff->lock); if (!avail_video && !avail_audio) { slock_lock(ff->cond_lock); if (ff->can_sleep) { ff->can_sleep = false; scond_wait(ff->cond, ff->cond_lock); ff->can_sleep = true; } else scond_signal(ff->cond); slock_unlock(ff->cond_lock); } if (avail_video) { slock_lock(ff->lock); fifo_read(ff->attr_fifo, &attr_buf, sizeof(attr_buf)); fifo_read(ff->video_fifo, video_buf, attr_buf.height * attr_buf.pitch); slock_unlock(ff->lock); scond_signal(ff->cond); attr_buf.data = video_buf; ffmpeg_push_video_thread(ff, &attr_buf); } if (avail_audio) { slock_lock(ff->lock); fifo_read(ff->audio_fifo, audio_buf, audio_buf_size); slock_unlock(ff->lock); scond_signal(ff->cond); struct ffemu_audio_data aud = {0}; aud.frames = ff->audio.codec->frame_size; aud.data = audio_buf; ffmpeg_push_audio_thread(ff, &aud, true); } } av_free(video_buf); av_free(audio_buf); }