diff options
Diffstat (limited to 'src/codec')
| -rw-r--r-- | src/codec/codec.h | 18 | ||||
| -rw-r--r-- | src/codec/ffmpeg/decoder.c | 9 | ||||
| -rw-r--r-- | src/codec/ffmpeg/decoder.h | 4 | ||||
| -rw-r--r-- | src/codec/ffmpeg/demuxer.c | 35 | ||||
| -rw-r--r-- | src/codec/ffmpeg/packet_ext.c | 39 | ||||
| -rw-r--r-- | src/codec/ffmpeg/packet_ext.h | 1 | ||||
| -rw-r--r-- | src/codec/ffmpeg/scaler.c | 18 | ||||
| -rw-r--r-- | src/codec/ffmpeg/scaler.h | 2 |
8 files changed, 91 insertions, 35 deletions
diff --git a/src/codec/codec.h b/src/codec/codec.h index 6fd42e9..4b93673 100644 --- a/src/codec/codec.h +++ b/src/codec/codec.h @@ -29,7 +29,8 @@ enum { CAMU_STREAM_UNKNOWN = AVMEDIA_TYPE_UNKNOWN, CAMU_STREAM_AUDIO = AVMEDIA_TYPE_AUDIO, CAMU_STREAM_VIDEO = AVMEDIA_TYPE_VIDEO, - CAMU_STREAM_SUBTITLE = AVMEDIA_TYPE_SUBTITLE + CAMU_STREAM_SUBTITLE = AVMEDIA_TYPE_SUBTITLE, + CAMU_STREAM_ATTACHMENT = AVMEDIA_TYPE_ATTACHMENT }; enum { CAMU_SAMPLE_FORMAT_NONE = AV_SAMPLE_FMT_NONE, @@ -52,6 +53,7 @@ enum { CAMU_PIXEL_FORMAT_GREYA = AV_PIX_FMT_GRAY8A, CAMU_PIXEL_FORMAT_GREY = AV_PIX_FMT_GRAY8 }; +#define CAMU_NUM_DATA_POINTERS AV_NUM_DATA_POINTERS #else enum { CAMU_OK = 0, @@ -66,7 +68,8 @@ enum { CAMU_STREAM_UNKNOWN = 0, CAMU_STREAM_AUDIO, CAMU_STREAM_VIDEO, - CAMU_STREAM_SUBTITLE + CAMU_STREAM_SUBTITLE, + CAMU_STREAM_ATTACHMENT }; enum { CAMU_SAMPLE_FORMAT_NONE = -1, @@ -89,6 +92,7 @@ enum { CAMU_PIXEL_FORMAT_GREYA, CAMU_PIXEL_FORMAT_GREY }; +#define CAMU_NUM_DATA_POINTERS 8 #endif enum { @@ -204,7 +208,7 @@ struct camu_scaler_format { struct camu_scaler { bool (*init)(struct camu_scaler *, struct camu_scaler_format *); bool (*scale)(struct camu_scaler *, const u8 **in_slice, s32 *in_strides); - AVFrame *(*get_frame)(struct camu_scaler *); + struct camu_codec_frame *(*get_frame)(struct camu_scaler *); void (*free)(struct camu_scaler **); }; @@ -276,7 +280,7 @@ static inline f64 camu_audio_format_samples_to_sec(struct camu_audio_format *fmt return samples / (f64)fmt->sample_rate; } -static inline size_t camu_audio_format_usec_to_bytes(struct camu_audio_format *fmt, size_t usec) +static inline size_t camu_audio_format_usec_to_bytes(struct camu_audio_format *fmt, u64 usec) { // Keep order of operations for precision. size_t samples = usec * (fmt->sample_rate / 1000000.0); @@ -289,6 +293,12 @@ static inline size_t camu_audio_format_sec_to_bytes(struct camu_audio_format *fm return samples * camu_audio_format_bytes_per_sample(fmt) * fmt->channel_count; } +static inline u64 camu_audio_format_bytes_to_usec(struct camu_audio_format *fmt, size_t bytes) +{ + size_t samples = bytes / (camu_audio_format_bytes_per_sample(fmt) * fmt->channel_count); + return samples / (fmt->sample_rate / 1000000.0); +} + static inline f64 camu_audio_format_bytes_to_sec(struct camu_audio_format *fmt, size_t bytes) { size_t samples = bytes / (camu_audio_format_bytes_per_sample(fmt) * fmt->channel_count); diff --git a/src/codec/ffmpeg/decoder.c b/src/codec/ffmpeg/decoder.c index d3ab3b2..0fb60ac 100644 --- a/src/codec/ffmpeg/decoder.c +++ b/src/codec/ffmpeg/decoder.c @@ -37,10 +37,11 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend } s32 cpus = av_cpu_count(); - if (cpus > 4) cpus = 2; + if (cpus >= 8) cpus = 4; av->codec_context->thread_count = cpus / 2; // FF_THREAD_FRAME or FF_THREAD_SLICE. - av->codec_context->thread_type = FF_THREAD_SLICE; + //av->codec_context->thread_type = FF_THREAD_SLICE; + av->codec_context->thread_type = FF_THREAD_FRAME; al_log_debug("ff_decoder", "Using %i threads for decoder.", cpus); #if !defined CAMU_SINK_NO_VIDEO && defined CAMU_RENDERER_VULKAN @@ -61,8 +62,8 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend s64 kbps = codecpar->bit_rate > 0 ? codecpar->bit_rate / 1000L : 0L; al_log_info("ff_decoder", "Codec: %s (%s) %ldkbps.", codec->name, long_name, kbps); - av->time_base = stream->av.stream->time_base; - av->duration = stream->av.stream->duration; + //av->duration = stream->duration; + //av->time_base = stream->av.stream->time_base; //av->last_pts = 0; //av->last_duration = 0; //av->seek_pos = -1; diff --git a/src/codec/ffmpeg/decoder.h b/src/codec/ffmpeg/decoder.h index 88bbd4c..2e35bb1 100644 --- a/src/codec/ffmpeg/decoder.h +++ b/src/codec/ffmpeg/decoder.h @@ -8,8 +8,8 @@ struct camu_ff_decoder { struct camu_decoder dec; AVCodecContext *codec_context; - AVRational time_base; - u64 duration; + //AVRational time_base; + //u64 duration; //s64 last_pts; //s64 last_duration; //s64 seek_pos; diff --git a/src/codec/ffmpeg/demuxer.c b/src/codec/ffmpeg/demuxer.c index 8ea645b..24c1ba6 100644 --- a/src/codec/ffmpeg/demuxer.c +++ b/src/codec/ffmpeg/demuxer.c @@ -77,28 +77,31 @@ static bool ff_demuxer_init(struct camu_demuxer *demux, struct cch_handle *handl for (u32 i = 0; i < av->format_context->nb_streams; i++) { AVStream *stream = av->format_context->streams[i]; enum AVMediaType type = stream->codecpar->codec_type; - if (type != AVMEDIA_TYPE_AUDIO && type != AVMEDIA_TYPE_VIDEO) type = AVMEDIA_TYPE_UNKNOWN; - // Try to detect attached images. - if (type == AVMEDIA_TYPE_VIDEO && GUESS_STREAM_IS_IMAGE(stream)) { - al_log_info("ff_demuxer", "Guessing that stream #%u is an image.", i); - stream->duration = 0; - } else if (stream->duration < 0) { - al_log_warn("ff_demuxer", "Stream #%u has an invalid duration (%ld).", i, stream->duration); - if (av->format_context->duration < 0) { - stream->duration = 0; + u64 duration = 0; + if (type == AVMEDIA_TYPE_AUDIO || type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_SUBTITLE) { + // Try to detect attached images. + if (type == AVMEDIA_TYPE_VIDEO && GUESS_STREAM_IS_IMAGE(stream)) { + al_log_info("ff_demuxer", "Guessing that stream #%u is an image.", i); } else { - stream->duration = av_rescale_q(av->format_context->duration, AV_TIME_BASE_Q, stream->time_base); + if (stream->duration < 0) { + al_log_warn("ff_demuxer", "Stream #%u has an invalid duration (%ld).", i, stream->duration); + stream->duration = av->format_context->duration < 0 ? 0 : + av_rescale_q(av->format_context->duration, AV_TIME_BASE_Q, stream->time_base); + al_log_info("ff_demuxer", "Defaulting stream #%u to a duration of %.3fs.", + i, stream->duration * av_q2d(stream->time_base)); + al_assert(stream->duration >= 0); + } + duration = (u64)av_rescale_q(stream->duration, stream->time_base, AV_TIME_BASE_Q); + if (duration > av->duration) av->duration = duration; } - al_log_info("ff_demuxer", "Setting stream #%u to a duration of %.3fs.", i, stream->duration * av_q2d(stream->time_base)); + if (stream->start_time == AV_NOPTS_VALUE) stream->start_time = 0; + } else if (type != AVMEDIA_TYPE_ATTACHMENT) { + continue; } - if (stream->start_time == AV_NOPTS_VALUE) stream->start_time = 0; - s64 duration = av_rescale_q(stream->duration, stream->time_base, AV_TIME_BASE_Q); - al_assert(duration >= 0); - if ((u64)duration > av->duration) av->duration = (u64)duration; al_array_push(av->demux.streams, ((struct camu_codec_stream){ .mode = CAMU_FFMPEG_COMPAT, .type = type, - .duration = (u64)duration, + .duration = duration, .av.stream = stream })); } diff --git a/src/codec/ffmpeg/packet_ext.c b/src/codec/ffmpeg/packet_ext.c index c0e400d..16f5748 100644 --- a/src/codec/ffmpeg/packet_ext.c +++ b/src/codec/ffmpeg/packet_ext.c @@ -38,6 +38,23 @@ void aki_packet_write_av_codec_id(struct aki_packet *packet, enum AVCodecID code AKI_PACKET_WRITE_TYPE(packet, enum AVCodecID, codec_id); } +void aki_packet_write_av_dictionary(struct aki_packet *packet, AVDictionary *dict) +{ + s32 count = av_dict_count(dict); + AKI_PACKET_WRITE_TYPE(packet, s32, count); + const AVDictionaryEntry *entry = NULL; + while ((entry = av_dict_iterate(dict, entry))) { + size_t len = al_strlen(entry->key); + al_assert(len <= UINT32_MAX); + AKI_PACKET_WRITE_TYPE(packet, u32, len); + AKI_PACKET_WRITE_DATA(packet, entry->key, len); + len = al_strlen(entry->value); + al_assert(len <= UINT32_MAX); + AKI_PACKET_WRITE_TYPE(packet, u32, len); + AKI_PACKET_WRITE_DATA(packet, entry->value, len); + } +} + void aki_packet_write_av_stream(struct aki_packet *packet, AVStream *stream) { AKI_PACKET_WRITE_TYPE(packet, s32, stream->index); @@ -46,6 +63,7 @@ void aki_packet_write_av_stream(struct aki_packet *packet, AVStream *stream) AKI_PACKET_WRITE_TYPE(packet, s64, stream->duration); AKI_PACKET_WRITE_TYPE(packet, s64, stream->start_time); AKI_PACKET_WRITE_TYPE(packet, s64, stream->nb_frames); + aki_packet_write_av_dictionary(packet, stream->metadata); if (stream->avg_frame_rate.den == 0) { // r_frame_rate.den == 0 handled on the client. AKI_PACKET_WRITE_TYPE(packet, AVRational, stream->r_frame_rate); @@ -118,6 +136,25 @@ enum AVCodecID aki_packet_read_av_codec_id(struct aki_packet *packet) return id; } +void aki_packet_read_av_dictionary(struct aki_packet *packet, AVDictionary **dict) +{ + s32 count; + AKI_PACKET_READ_TYPE(packet, s32, count); + for (s32 i = 0; i < count; i++) { + char *key, *value; + u32 len; + AKI_PACKET_READ_TYPE(packet, u32, len); + AKI_PACKET_READ_DATA(packet, len, key); + // Key and value MUST be allocated with av_malloc functions + // just like all FFmpeg structures. + key = av_strndup(key, len); + AKI_PACKET_READ_TYPE(packet, u32, len); + AKI_PACKET_READ_DATA(packet, len, value); + value = av_strndup(value, len); + av_dict_set(dict, key, value, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + } +} + AVStream *aki_packet_read_av_stream(AVFormatContext *format_context, const AVCodec *codec, struct aki_packet *packet) { AVStream *stream = avformat_new_stream(format_context, codec); @@ -127,6 +164,8 @@ AVStream *aki_packet_read_av_stream(AVFormatContext *format_context, const AVCod AKI_PACKET_READ_TYPE(packet, s64, stream->duration); AKI_PACKET_READ_TYPE(packet, s64, stream->start_time); AKI_PACKET_READ_TYPE(packet, s64, stream->nb_frames); + stream->metadata = NULL; + aki_packet_read_av_dictionary(packet, &stream->metadata); AKI_PACKET_READ_TYPE(packet, AVRational, stream->avg_frame_rate); return stream; } diff --git a/src/codec/ffmpeg/packet_ext.h b/src/codec/ffmpeg/packet_ext.h index 36b6ed5..26a1392 100644 --- a/src/codec/ffmpeg/packet_ext.h +++ b/src/codec/ffmpeg/packet_ext.h @@ -6,6 +6,7 @@ #include <libavcodec/packet.h> #include <libavcodec/codec_par.h> #include <libavformat/avformat.h> +#include <libavutil/dict.h> void aki_packet_write_av_codec_parameters(struct aki_packet *packet, AVCodecParameters *codecpar); void aki_packet_write_av_codec_id(struct aki_packet *packet, enum AVCodecID codec_id); diff --git a/src/codec/ffmpeg/scaler.c b/src/codec/ffmpeg/scaler.c index d233268..0089dd1 100644 --- a/src/codec/ffmpeg/scaler.c +++ b/src/codec/ffmpeg/scaler.c @@ -49,11 +49,12 @@ static bool ff_scaler_init(struct camu_scaler *scale, struct camu_scaler_format return false; } - av->frame = alloc_picture(fmt->req.format, fmt->req.width, fmt->req.height); - if (!av->frame) { + AVFrame *frame = alloc_picture(fmt->req.format, fmt->req.width, fmt->req.height); + if (!frame) { al_log_error("ff_scaler", "Failed to allocate frame."); return false; } + av->frame.av.frame = frame; return true; } @@ -61,8 +62,9 @@ static bool ff_scaler_init(struct camu_scaler *scale, struct camu_scaler_format static bool ff_scaler_scale(struct camu_scaler *scale, const u8 **in_slice, s32 *in_strides) { struct camu_ff_scaler *av = (struct camu_ff_scaler *)scale; - s32 ret = sws_scale(av->scaler_context, in_slice, in_strides, 0, av->fmt.in.height, - av->frame->data, av->frame->linesize); + AVFrame *frame = av->frame.av.frame; + s32 ret = sws_scale(av->scaler_context, in_slice, in_strides, 0, + av->fmt.in.height, frame->data, frame->linesize); if (ret != av->fmt.req.height) { al_log_error("ff_scaler", "Failed to scale frame (%s).", av_err2str(ret)); return false; @@ -70,17 +72,17 @@ static bool ff_scaler_scale(struct camu_scaler *scale, const u8 **in_slice, s32 return true; } -static AVFrame *ff_scaler_get_frame(struct camu_scaler *scale) +static struct camu_codec_frame *ff_scaler_get_frame(struct camu_scaler *scale) { struct camu_ff_scaler *av = (struct camu_ff_scaler *)scale; - return av->frame; + return &av->frame; } static void ff_scaler_free(struct camu_scaler **scale) { struct camu_ff_scaler *av = (struct camu_ff_scaler *)*scale; - av_freep(&av->frame->data[0]); - av_frame_free(&av->frame); + av_freep(&av->frame.av.frame->data[0]); + av_frame_free(&av->frame.av.frame); sws_freeContext(av->scaler_context); al_free(av); *scale = NULL; diff --git a/src/codec/ffmpeg/scaler.h b/src/codec/ffmpeg/scaler.h index a4effb3..f01f3fd 100644 --- a/src/codec/ffmpeg/scaler.h +++ b/src/codec/ffmpeg/scaler.h @@ -9,7 +9,7 @@ struct camu_ff_scaler { struct camu_scaler scale; struct SwsContext *scaler_context; struct camu_scaler_format fmt; - AVFrame *frame; + struct camu_codec_frame frame; }; struct camu_scaler *camu_ff_scaler_create(void); |