mirror of
https://github.com/libretro/RetroArch
synced 2025-03-20 19:21:27 +00:00
Merge pull request #9786 from hasenbanck/ffmpeg-amf
Implement ffmpeg send/receive encoding API
This commit is contained in:
commit
12ae92ef66
@ -1190,38 +1190,51 @@ static bool ffmpeg_push_audio(void *data,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool encode_video(ffmpeg_t *handle, AVPacket *pkt, AVFrame *frame)
|
static bool encode_video(ffmpeg_t *handle, AVFrame *frame)
|
||||||
{
|
{
|
||||||
int got_packet = 0;
|
AVPacket pkt;
|
||||||
|
int ret;
|
||||||
|
|
||||||
av_init_packet(pkt);
|
av_init_packet(&pkt);
|
||||||
pkt->data = handle->video.outbuf;
|
pkt.data = handle->video.outbuf;
|
||||||
pkt->size = handle->video.outbuf_size;
|
pkt.size = handle->video.outbuf_size;
|
||||||
|
|
||||||
if (avcodec_encode_video2(handle->video.codec, pkt, frame, &got_packet) < 0)
|
ret = avcodec_send_frame(handle->video.codec, frame);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
RARCH_ERR("[FFmpeg]: Cannot send video frame. Error code: %s.\n", av_err2str(ret));
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!got_packet)
|
|
||||||
{
|
|
||||||
pkt->size = 0;
|
|
||||||
pkt->pts = AV_NOPTS_VALUE;
|
|
||||||
pkt->dts = AV_NOPTS_VALUE;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkt->pts != (int64_t)AV_NOPTS_VALUE)
|
while (ret >= 0)
|
||||||
{
|
{
|
||||||
pkt->pts = av_rescale_q(pkt->pts, handle->video.codec->time_base,
|
ret = avcodec_receive_packet(handle->video.codec, &pkt);
|
||||||
handle->muxer.vstream->time_base);
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
}
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (ret < 0)
|
||||||
|
{
|
||||||
|
RARCH_ERR("[FFmpeg]: Cannot receive video packet. Error code: %s.\n", av_err2str(ret));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (pkt->dts != (int64_t)AV_NOPTS_VALUE)
|
pkt.pts = av_rescale_q(pkt.pts, handle->video.codec->time_base,
|
||||||
{
|
handle->muxer.vstream->time_base);
|
||||||
pkt->dts = av_rescale_q(pkt->dts, handle->video.codec->time_base,
|
|
||||||
handle->muxer.vstream->time_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt->stream_index = handle->muxer.vstream->index;
|
pkt.dts = av_rescale_q(pkt.dts,
|
||||||
|
handle->video.codec->time_base,
|
||||||
|
handle->muxer.vstream->time_base);
|
||||||
|
|
||||||
|
pkt.stream_index = handle->muxer.vstream->index;
|
||||||
|
|
||||||
|
ret = av_interleaved_write_frame(handle->muxer.ctx, &pkt);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
RARCH_ERR("[FFmpeg]: Cannot write video packet to output file. Error code: %s.\n", av_err2str(ret));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1265,22 +1278,14 @@ static void ffmpeg_scale_input(ffmpeg_t *handle,
|
|||||||
static bool ffmpeg_push_video_thread(ffmpeg_t *handle,
|
static bool ffmpeg_push_video_thread(ffmpeg_t *handle,
|
||||||
const struct record_video_data *vid)
|
const struct record_video_data *vid)
|
||||||
{
|
{
|
||||||
AVPacket pkt;
|
|
||||||
|
|
||||||
if (!vid->is_dupe)
|
if (!vid->is_dupe)
|
||||||
ffmpeg_scale_input(handle, vid);
|
ffmpeg_scale_input(handle, vid);
|
||||||
|
|
||||||
handle->video.conv_frame->pts = handle->video.frame_cnt;
|
handle->video.conv_frame->pts = handle->video.frame_cnt;
|
||||||
|
|
||||||
if (!encode_video(handle, &pkt, handle->video.conv_frame))
|
if (!encode_video(handle, handle->video.conv_frame))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (pkt.size)
|
|
||||||
{
|
|
||||||
if (av_interleaved_write_frame(handle->muxer.ctx, &pkt) < 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
handle->video.frame_cnt++;
|
handle->video.frame_cnt++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1333,15 +1338,16 @@ static void planarize_audio(ffmpeg_t *handle)
|
|||||||
handle->audio.frames_in_buffer);
|
handle->audio.frames_in_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool encode_audio(ffmpeg_t *handle, AVPacket *pkt, bool dry)
|
static bool encode_audio(ffmpeg_t *handle, bool dry)
|
||||||
{
|
{
|
||||||
AVFrame *frame;
|
AVFrame *frame;
|
||||||
|
AVPacket pkt;
|
||||||
int samples_size;
|
int samples_size;
|
||||||
int got_packet = 0;
|
int ret;
|
||||||
|
|
||||||
av_init_packet(pkt);
|
av_init_packet(&pkt);
|
||||||
pkt->data = handle->audio.outbuf;
|
pkt.data = handle->audio.outbuf;
|
||||||
pkt->size = handle->audio.outbuf_size;
|
pkt.size = handle->audio.outbuf_size;
|
||||||
|
|
||||||
frame = av_frame_alloc();
|
frame = av_frame_alloc();
|
||||||
if (!frame)
|
if (!frame)
|
||||||
@ -1365,39 +1371,48 @@ static bool encode_audio(ffmpeg_t *handle, AVPacket *pkt, bool dry)
|
|||||||
handle->audio.buffer,
|
handle->audio.buffer,
|
||||||
samples_size, 0);
|
samples_size, 0);
|
||||||
|
|
||||||
if (avcodec_encode_audio2(handle->audio.codec,
|
ret = avcodec_send_frame(handle->audio.codec, dry ? NULL : frame);
|
||||||
pkt, dry ? NULL : frame, &got_packet) < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
|
RARCH_ERR("[FFmpeg]: Cannot send audio frame. Return code: %s.\n", av_err2str(ret));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!got_packet)
|
while (ret >= 0)
|
||||||
{
|
{
|
||||||
pkt->size = 0;
|
ret = avcodec_receive_packet(handle->audio.codec, &pkt);
|
||||||
pkt->pts = AV_NOPTS_VALUE;
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
pkt->dts = AV_NOPTS_VALUE;
|
{
|
||||||
av_frame_free(&frame);
|
break;
|
||||||
return true;
|
}
|
||||||
}
|
else if (ret < 0)
|
||||||
|
{
|
||||||
|
av_frame_free(&frame);
|
||||||
|
RARCH_ERR("[FFmpeg]: Cannot receive audio packet. Return code: %s.\n", av_err2str(ret));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (pkt->pts != (int64_t)AV_NOPTS_VALUE)
|
pkt.pts = av_rescale_q(pkt.pts,
|
||||||
{
|
handle->audio.codec->time_base,
|
||||||
pkt->pts = av_rescale_q(pkt->pts,
|
handle->muxer.astream->time_base);
|
||||||
handle->audio.codec->time_base,
|
|
||||||
handle->muxer.astream->time_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pkt->dts != (int64_t)AV_NOPTS_VALUE)
|
pkt.dts = av_rescale_q(pkt.dts,
|
||||||
{
|
handle->audio.codec->time_base,
|
||||||
pkt->dts = av_rescale_q(pkt->dts,
|
handle->muxer.astream->time_base);
|
||||||
handle->audio.codec->time_base,
|
|
||||||
handle->muxer.astream->time_base);
|
pkt.stream_index = handle->muxer.astream->index;
|
||||||
|
|
||||||
|
ret = av_interleaved_write_frame(handle->muxer.ctx, &pkt);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
av_frame_free(&frame);
|
||||||
|
RARCH_ERR("[FFmpeg]: Cannot write video packet to output file. Error code: %s.\n", av_err2str(ret));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
|
|
||||||
pkt->stream_index = handle->muxer.astream->index;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1474,7 +1489,6 @@ static bool ffmpeg_push_audio_thread(ffmpeg_t *handle,
|
|||||||
|
|
||||||
while (written_frames < aud->frames)
|
while (written_frames < aud->frames)
|
||||||
{
|
{
|
||||||
AVPacket pkt;
|
|
||||||
size_t can_write = handle->audio.codec->frame_size -
|
size_t can_write = handle->audio.codec->frame_size -
|
||||||
handle->audio.frames_in_buffer;
|
handle->audio.frames_in_buffer;
|
||||||
size_t write_left = aud->frames - written_frames;
|
size_t write_left = aud->frames - written_frames;
|
||||||
@ -1498,19 +1512,12 @@ static bool ffmpeg_push_audio_thread(ffmpeg_t *handle,
|
|||||||
< (size_t)handle->audio.codec->frame_size) && require_block)
|
< (size_t)handle->audio.codec->frame_size) && require_block)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!encode_audio(handle, &pkt, false))
|
if (!encode_audio(handle, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
handle->audio.frame_cnt += handle->audio.frames_in_buffer;
|
handle->audio.frame_cnt += handle->audio.frames_in_buffer;
|
||||||
handle->audio.frames_in_buffer = 0;
|
handle->audio.frames_in_buffer = 0;
|
||||||
|
|
||||||
if (pkt.size)
|
|
||||||
{
|
|
||||||
if (av_interleaved_write_frame(handle->muxer.ctx, &pkt) < 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1531,24 +1538,13 @@ static void ffmpeg_flush_audio(ffmpeg_t *handle, void *audio_buf,
|
|||||||
ffmpeg_push_audio_thread(handle, &aud, false);
|
ffmpeg_push_audio_thread(handle, &aud, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
encode_audio(handle, true);
|
||||||
{
|
|
||||||
AVPacket pkt;
|
|
||||||
if (!encode_audio(handle, &pkt, true) || !pkt.size ||
|
|
||||||
av_interleaved_write_frame(handle->muxer.ctx, &pkt) < 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void ffmpeg_flush_video(ffmpeg_t *handle)
|
static void ffmpeg_flush_video(ffmpeg_t *handle)
|
||||||
{
|
{
|
||||||
for (;;)
|
encode_video(handle, NULL);
|
||||||
{
|
|
||||||
AVPacket pkt;
|
|
||||||
if (!encode_video(handle, &pkt, NULL) || !pkt.size ||
|
|
||||||
av_interleaved_write_frame(handle->muxer.ctx, &pkt) < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ffmpeg_flush_buffers(ffmpeg_t *handle)
|
static void ffmpeg_flush_buffers(ffmpeg_t *handle)
|
||||||
@ -1579,11 +1575,10 @@ static void ffmpeg_flush_buffers(ffmpeg_t *handle)
|
|||||||
struct record_audio_data aud = {0};
|
struct record_audio_data aud = {0};
|
||||||
|
|
||||||
fifo_read(handle->audio_fifo, audio_buf, audio_buf_size);
|
fifo_read(handle->audio_fifo, audio_buf, audio_buf_size);
|
||||||
|
|
||||||
aud.frames = handle->audio.codec->frame_size;
|
aud.frames = handle->audio.codec->frame_size;
|
||||||
aud.data = audio_buf;
|
aud.data = audio_buf;
|
||||||
|
|
||||||
ffmpeg_push_audio_thread(handle, &aud, true);
|
ffmpeg_push_audio_thread(handle, &aud, true);
|
||||||
|
|
||||||
did_work = true;
|
did_work = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user