summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTuomas Virtanen <katajakasa@gmail.com>2018-10-07 21:00:45 +0300
committerTuomas Virtanen <katajakasa@gmail.com>2018-10-07 21:00:45 +0300
commit76bc8c49d46be38f6d4a65a810f8ef64923daef9 (patch)
tree4b24e74fcb5a65f24e59dcf97d9afd8200109c2b
parent25747441205f7973ea8815f1014372378ff34858 (diff)
Some initial work on supporting new ffmpeg decoder API
-rw-r--r--CMakeLists.txt2
-rw-r--r--include/kitchensink/internal/kitdecoder.h5
-rw-r--r--src/internal/audio/kitaudio.c82
-rw-r--r--src/internal/kitdecoder.c33
-rw-r--r--src/internal/subtitle/kitsubtitle.c10
-rw-r--r--src/internal/video/kitvideo.c70
6 files changed, 182 insertions, 20 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0922eaa..56d511c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,7 @@ add_definitions(
)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
-set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -Werror -fno-omit-frame-pointer -Wno-deprecated-declarations")
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -Werror -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -ggdb -O2 -fno-omit-frame-pointer -DNDEBUG")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2 -DNDEBUG")
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -Os -DNDEBUG")
diff --git a/include/kitchensink/internal/kitdecoder.h b/include/kitchensink/internal/kitdecoder.h
index 74134b0..17e1e4b 100644
--- a/include/kitchensink/internal/kitdecoder.h
+++ b/include/kitchensink/internal/kitdecoder.h
@@ -21,7 +21,7 @@ enum {
typedef struct Kit_Decoder Kit_Decoder;
-typedef void (*dec_decode_cb)(Kit_Decoder *dec, AVPacket *in_packet);
+typedef int (*dec_decode_cb)(Kit_Decoder *dec, AVPacket *in_packet);
typedef void (*dec_close_cb)(Kit_Decoder *dec);
typedef void (*dec_free_packet_cb)(void *packet);
@@ -61,8 +61,11 @@ KIT_LOCAL bool Kit_CanWriteDecoderInput(Kit_Decoder *dec);
KIT_LOCAL int Kit_WriteDecoderInput(Kit_Decoder *dec, AVPacket *packet);
KIT_LOCAL AVPacket* Kit_ReadDecoderInput(Kit_Decoder *dec);
KIT_LOCAL void Kit_ClearDecoderInput(Kit_Decoder *dec);
+KIT_LOCAL AVPacket* Kit_PeekDecoderInput(Kit_Decoder *dec);
+KIT_LOCAL void Kit_AdvanceDecoderInput(Kit_Decoder *dec);
KIT_LOCAL int Kit_WriteDecoderOutput(Kit_Decoder *dec, void *packet);
+KIT_LOCAL bool Kit_CanWriteDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void* Kit_PeekDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void* Kit_ReadDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void Kit_AdvanceDecoderOutput(Kit_Decoder *dec);
diff --git a/src/internal/audio/kitaudio.c b/src/internal/audio/kitaudio.c
index 3a534bb..4bc284d 100644
--- a/src/internal/audio/kitaudio.c
+++ b/src/internal/audio/kitaudio.c
@@ -104,9 +104,13 @@ static void free_out_audio_packet_cb(void *packet) {
free(p);
}
-static void dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
+static int dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
assert(dec != NULL);
- assert(in_packet != NULL);
+
+ if(in_packet == NULL) {
+ return 0;
+ }
Kit_AudioDecoder *audio_dec = dec->userdata;
int frame_finished;
@@ -117,13 +121,13 @@ static void dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
int dst_bufsize;
double pts;
unsigned char **dst_data;
- Kit_AudioPacket *out_packet;
+ Kit_AudioPacket *out_packet = NULL;
// Decode as long as there is data
while(in_packet->size > 0) {
len = avcodec_decode_audio4(dec->codec_ctx, audio_dec->scratch_frame, &frame_finished, in_packet);
if(len < 0) {
- return;
+ return 0;
}
if(frame_finished) {
@@ -175,7 +179,77 @@ static void dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
in_packet->size -= len;
in_packet->data += len;
}
+ return 0;
+}
+#else
+static int dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+ assert(dec != NULL);
+ assert(in_packet != NULL);
+
+ Kit_AudioDecoder *audio_dec = dec->userdata;
+ int ret;
+ int len;
+ int dst_linesize;
+ int dst_nb_samples;
+ int dst_bufsize;
+ double pts;
+ unsigned char **dst_data;
+ Kit_AudioPacket *out_packet = NULL;
+
+ // Write packet to the decoder for handling.
+ ret = avcodec_send_packet(dec->codec_ctx, in_packet);
+ if(ret < 0) {
+ return 1;
+ }
+
+ // Pull decoded frames out when ready and if we have room in decoder output buffer
+ while(!ret && Kit_CanWriteDecoderOutput(dec)) {
+ ret = avcodec_receive_frame(dec->codec_ctx, audio_dec->scratch_frame);
+ if(!ret) {
+ dst_nb_samples = av_rescale_rnd(
+ audio_dec->scratch_frame->nb_samples,
+ dec->output.samplerate, // Target samplerate
+ dec->codec_ctx->sample_rate, // Source samplerate
+ AV_ROUND_UP);
+
+ av_samples_alloc_array_and_samples(
+ &dst_data,
+ &dst_linesize,
+ dec->output.channels,
+ dst_nb_samples,
+ _FindAVSampleFormat(dec->output.format),
+ 0);
+
+ len = swr_convert(
+ audio_dec->swr,
+ dst_data,
+ audio_dec->scratch_frame->nb_samples,
+ (const unsigned char **)audio_dec->scratch_frame->extended_data,
+ audio_dec->scratch_frame->nb_samples);
+
+ dst_bufsize = av_samples_get_buffer_size(
+ &dst_linesize,
+ dec->output.channels,
+ len,
+ _FindAVSampleFormat(dec->output.format), 1);
+
+ // Get presentation timestamp
+ pts = audio_dec->scratch_frame->best_effort_timestamp;
+ pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
+
+ // Lock, write to audio buffer, unlock
+ out_packet = _CreateAudioPacket(
+ (char*)dst_data[0], (size_t)dst_bufsize, pts);
+ Kit_WriteDecoderOutput(dec, out_packet);
+
+ // Free temps
+ av_freep(&dst_data[0]);
+ av_freep(&dst_data);
+ }
+ }
+ return 0;
}
+#endif
static void dec_close_audio_cb(Kit_Decoder *dec) {
if(dec == NULL) return;
diff --git a/src/internal/kitdecoder.c b/src/internal/kitdecoder.c
index 09e46d3..426e32c 100644
--- a/src/internal/kitdecoder.c
+++ b/src/internal/kitdecoder.c
@@ -156,17 +156,18 @@ int Kit_RunDecoder(Kit_Decoder *dec) {
}
// Then, see if we have incoming data
- in_packet = Kit_ReadDecoderInput(dec);
+ in_packet = Kit_PeekDecoderInput(dec);
if(in_packet == NULL) {
return 0;
}
// Run decoder with incoming packet
- dec->dec_decode(dec, in_packet);
-
- // Free raw packet before returning
- av_packet_free(&in_packet);
- return 1;
+ if(dec->dec_decode(dec, in_packet) == 0) {
+ Kit_AdvanceDecoderInput(dec);
+ av_packet_free(&in_packet);
+ return 1;
+ }
+ return 0;
}
// ---- Information API ----
@@ -228,6 +229,16 @@ AVPacket* Kit_ReadDecoderInput(Kit_Decoder *dec) {
return Kit_ReadBuffer(dec->buffer[KIT_DEC_BUF_IN]);
}
+AVPacket* Kit_PeekDecoderInput(Kit_Decoder *dec) {
+ assert(dec != NULL);
+ return Kit_PeekBuffer(dec->buffer[KIT_DEC_BUF_IN]);
+}
+
+void Kit_AdvanceDecoderInput(Kit_Decoder *dec) {
+ assert(dec != NULL);
+ Kit_AdvanceBuffer(dec->buffer[KIT_DEC_BUF_IN]);
+}
+
void Kit_ClearDecoderInput(Kit_Decoder *dec) {
Kit_ClearBuffer(dec->buffer[KIT_DEC_BUF_IN]);
}
@@ -271,6 +282,16 @@ void* Kit_ReadDecoderOutput(Kit_Decoder *dec) {
return ret;
}
+bool Kit_CanWriteDecoderOutput(Kit_Decoder *dec) {
+ assert(dec != NULL);
+ bool ret = false;
+ if(SDL_LockMutex(dec->output_lock) == 0) {
+ ret = !Kit_IsBufferFull(dec->buffer[KIT_DEC_BUF_OUT]);
+ SDL_UnlockMutex(dec->output_lock);
+ }
+ return ret;
+}
+
void Kit_ForEachDecoderOutput(Kit_Decoder *dec, Kit_ForEachItemCallback cb, void *userdata) {
assert(dec != NULL);
if(SDL_LockMutex(dec->output_lock) == 0) {
diff --git a/src/internal/subtitle/kitsubtitle.c b/src/internal/subtitle/kitsubtitle.c
index 417b338..bd28fac 100644
--- a/src/internal/subtitle/kitsubtitle.c
+++ b/src/internal/subtitle/kitsubtitle.c
@@ -29,9 +29,12 @@ static void free_out_subtitle_packet_cb(void *packet) {
Kit_FreeSubtitlePacket((Kit_SubtitlePacket*)packet);
}
-static void dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+static int dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
assert(dec != NULL);
- assert(in_packet != NULL);
+
+ if(in_packet == NULL) {
+ return 0;
+ }
Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
double pts;
@@ -43,7 +46,7 @@ static void dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
if(in_packet->size > 0) {
len = avcodec_decode_subtitle2(dec->codec_ctx, &subtitle_dec->scratch_frame, &frame_finished, in_packet);
if(len < 0) {
- return;
+ return 0;
}
if(frame_finished) {
@@ -70,6 +73,7 @@ static void dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
avsubtitle_free(&subtitle_dec->scratch_frame);
}
}
+ return 0;
}
static void dec_close_subtitle_cb(Kit_Decoder *dec) {
diff --git a/src/internal/video/kitvideo.c b/src/internal/video/kitvideo.c
index 568c178..112efc0 100644
--- a/src/internal/video/kitvideo.c
+++ b/src/internal/video/kitvideo.c
@@ -93,21 +93,25 @@ static void free_out_video_packet_cb(void *packet) {
free(p);
}
-static void dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
+static int dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
assert(dec != NULL);
- assert(in_packet != NULL);
+
+ if(in_packet == NULL) {
+ return 0;
+ }
Kit_VideoDecoder *video_dec = dec->userdata;
- AVFrame *out_frame;
+ AVFrame *out_frame = NULL;
+ Kit_VideoPacket *out_packet = NULL;
int frame_finished;
int len;
double pts;
- Kit_VideoPacket *out_packet;
while(in_packet->size > 0) {
len = avcodec_decode_video2(dec->codec_ctx, video_dec->scratch_frame, &frame_finished, in_packet);
if(len < 0) {
- return;
+ return 0;
}
if(frame_finished) {
@@ -146,7 +150,63 @@ static void dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
in_packet->size -= len;
in_packet->data += len;
}
+
+ return 0;
+}
+#else
+static int dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+ assert(dec != NULL);
+ assert(in_packet != NULL);
+
+ Kit_VideoDecoder *video_dec = dec->userdata;
+ AVFrame *out_frame = NULL;
+ Kit_VideoPacket *out_packet = NULL;
+ double pts;
+ int ret;
+
+ // Write packet to the decoder for handling.
+ ret = avcodec_send_packet(dec->codec_ctx, in_packet);
+ if(ret < 0) {
+ return 1;
+ }
+
+ // Pull decoded frames out when ready and if we have room in decoder output buffer
+ LOG("OUT\n");
+ while(!ret && Kit_CanWriteDecoderOutput(dec)) {
+ ret = avcodec_receive_frame(dec->codec_ctx, video_dec->scratch_frame);
+ LOG("DEC FRAME\n");
+ if(!ret) {
+ out_frame = av_frame_alloc();
+ av_image_alloc(
+ out_frame->data,
+ out_frame->linesize,
+ dec->codec_ctx->width,
+ dec->codec_ctx->height,
+ _FindAVPixelFormat(dec->output.format),
+ 1);
+
+ // Scale from source format to target format, don't touch the size
+ sws_scale(
+ video_dec->sws,
+ (const unsigned char * const *)video_dec->scratch_frame->data,
+ video_dec->scratch_frame->linesize,
+ 0,
+ dec->codec_ctx->height,
+ out_frame->data,
+ out_frame->linesize);
+
+ // Get presentation timestamp
+ pts = video_dec->scratch_frame->best_effort_timestamp;
+ pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
+
+ // Lock, write to audio buffer, unlock
+ out_packet = _CreateVideoPacket(out_frame, pts);
+ Kit_WriteDecoderOutput(dec, out_packet);
+ }
+ }
+ return 0;
}
+#endif
static void dec_close_video_cb(Kit_Decoder *dec) {
if(dec == NULL) return;