From 056901b2be67072f41315fce26e0f58e5569be9a Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 16 Jan 2016 21:19:52 +0100 Subject: video: refactor: disentangle decoding/filtering some more This moves some code related to decoding from video.c to dec_video.c, and also removes some accesses to dec_video.c from the filtering code. dec_video.ch is starting to make sense, and simply returns video frames from a demuxer stream. The API exposed is also somewhat intended to be easily changeable to move decoding to a separate thread, if we ever want this (due to libavcodec already being threaded, I don't see much of a reason, but it might still be helpful). --- video/decode/dec_video.c | 97 ++++++++++++++++++++++++++++++++++++++++++++---- video/decode/dec_video.h | 32 +++++++++++----- 2 files changed, 112 insertions(+), 17 deletions(-) (limited to 'video') diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c index 00af2e4c7b..f28871c6bb 100644 --- a/video/decode/dec_video.c +++ b/video/decode/dec_video.c @@ -29,6 +29,7 @@ #include "osdep/timer.h" #include "stream/stream.h" +#include "demux/demux.h" #include "demux/packet.h" #include "common/codecs.h" @@ -55,17 +56,19 @@ const vd_functions_t * const mpcodecs_vd_drivers[] = { NULL }; -void video_reset_decoding(struct dec_video *d_video) +void video_reset(struct dec_video *d_video) { video_vd_control(d_video, VDCTRL_RESET, NULL); - mp_image_unrefp(&d_video->waiting_decoded_mpi); d_video->num_buffered_pts = 0; - d_video->last_pts = MP_NOPTS_VALUE; d_video->first_packet_pdts = MP_NOPTS_VALUE; + d_video->start_pts = MP_NOPTS_VALUE; d_video->decoded_pts = MP_NOPTS_VALUE; d_video->codec_pts = MP_NOPTS_VALUE; d_video->codec_dts = MP_NOPTS_VALUE; d_video->last_format = d_video->fixed_format = (struct mp_image_params){0}; + d_video->dropped_frames = 0; + d_video->current_state = VIDEO_SKIP; + mp_image_unrefp(&d_video->current_mpi); } int video_vd_control(struct dec_video *d_video, int cmd, void *arg) @@ -78,7 +81,7 @@ int video_vd_control(struct dec_video *d_video, int cmd, void *arg) void video_uninit(struct dec_video *d_video) { - mp_image_unrefp(&d_video->waiting_decoded_mpi); + mp_image_unrefp(&d_video->current_mpi); mp_image_unrefp(&d_video->cover_art_mpi); if (d_video->vd_driver) { MP_VERBOSE(d_video, "Uninit video.\n"); @@ -125,7 +128,7 @@ static const struct vd_functions *find_driver(const char *name) bool video_init_best_codec(struct dec_video *d_video, char* video_decoders) { assert(!d_video->vd_driver); - video_reset_decoding(d_video); + video_reset(d_video); d_video->has_broken_packet_pts = -10; // needs 10 packets to reach decision struct mp_decoder_entry *decoder = NULL; @@ -258,9 +261,9 @@ static double retrieve_avi_pts(struct dec_video *d_video, double codec_pts) return MP_NOPTS_VALUE; } -struct mp_image *video_decode(struct dec_video *d_video, - struct demux_packet *packet, - int drop_frame) +static struct mp_image *decode_packet(struct dec_video *d_video, + struct demux_packet *packet, + int drop_frame) { struct MPOpts *opts = d_video->opts; bool avi_pts = d_video->header->codec->avi_dts && opts->correct_pts; @@ -364,3 +367,81 @@ void video_reset_aspect(struct dec_video *d_video) { d_video->last_format = (struct mp_image_params){0}; } + +void video_set_framedrop(struct dec_video *d_video, bool enabled) +{ + d_video->framedrop_enabled = enabled; +} + +// Frames before the start timestamp can be dropped. (Used for hr-seek.) +void video_set_start(struct dec_video *d_video, double start_pts) +{ + d_video->start_pts = start_pts; +} + +void video_work(struct dec_video *d_video) +{ + if (d_video->current_mpi) + return; + + if (d_video->header->attached_picture) { + if (d_video->current_state == VIDEO_SKIP && !d_video->cover_art_mpi) { + d_video->cover_art_mpi = + decode_packet(d_video, d_video->header->attached_picture, 0); + // Might need flush. + if (!d_video->cover_art_mpi) + d_video->cover_art_mpi = decode_packet(d_video, NULL, 0); + d_video->current_state = VIDEO_OK; + } + if (d_video->current_state == VIDEO_OK) + d_video->current_mpi = mp_image_new_ref(d_video->cover_art_mpi); + // (VIDEO_OK is returned the first time, when current_mpi is sill set) + d_video->current_state = VIDEO_EOF; + return; + } + + struct demux_packet *pkt; + if (demux_read_packet_async(d_video->header, &pkt) == 0) { + d_video->current_state = VIDEO_WAIT; + return; + } + + int framedrop_type = d_video->framedrop_enabled ? 1 : 0; + if (d_video->start_pts != MP_NOPTS_VALUE && pkt && + pkt->pts < d_video->start_pts - .005 && + !d_video->has_broken_packet_pts) + { + framedrop_type = 2; + } + d_video->current_mpi = decode_packet(d_video, pkt, framedrop_type); + bool had_packet = !!pkt; + talloc_free(pkt); + + d_video->current_state = VIDEO_OK; + if (!d_video->current_mpi) { + d_video->current_state = VIDEO_EOF; + if (had_packet) { + if (framedrop_type == 1) + d_video->dropped_frames += 1; + d_video->current_state = VIDEO_SKIP; + } + } +} + +// Fetch an image decoded with video_work(). Returns one of: +// VIDEO_OK: *out_mpi is set to a new image +// VIDEO_WAIT: waiting for demuxer; will receive a wakeup signal +// VIDEO_EOF: end of file, no more frames to be expected +// VIDEO_SKIP: dropped frame or something similar +int video_get_frame(struct dec_video *d_video, struct mp_image **out_mpi) +{ + *out_mpi = NULL; + if (d_video->current_mpi) { + *out_mpi = d_video->current_mpi; + d_video->current_mpi = NULL; + return VIDEO_OK; + } + if (d_video->current_state == VIDEO_OK) + return VIDEO_SKIP; + return d_video->current_state; +} diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h index dc2f62f4a4..3aba448219 100644 --- a/video/decode/dec_video.h +++ b/video/decode/dec_video.h @@ -37,11 +37,11 @@ struct dec_video { char *decoder_desc; - // Used temporarily during decoding (important for format changes) - struct mp_image *waiting_decoded_mpi; - struct mp_image_params decoder_output; // last output of the decoder + float fps; // FPS from demuxer or from user override - struct mp_image *cover_art_mpi; + int dropped_frames; + + // Internal (shared with vd_lavc.c). void *priv; // for free use by vd_driver @@ -57,6 +57,8 @@ struct dec_video { double buffered_pts[128]; int num_buffered_pts; + // Strictly internal (dec_video.c). + // PTS or DTS of packet first read double first_packet_pdts; @@ -66,13 +68,14 @@ struct dec_video { // Final PTS of previously decoded image double decoded_pts; - float fps; // FPS from demuxer or from user override - struct mp_image_params last_format, fixed_format; float initial_decoder_aspect; - // State used only by player/video.c - double last_pts; + double start_pts; + bool framedrop_enabled; + struct mp_image *cover_art_mpi; + struct mp_image *current_mpi; + int current_state; }; struct mp_decoder_list *video_decoder_list(void); @@ -80,13 +83,24 @@ struct mp_decoder_list *video_decoder_list(void); bool video_init_best_codec(struct dec_video *d_video, char* video_decoders); void video_uninit(struct dec_video *d_video); +void video_work(struct dec_video *d_video); + +void video_set_framedrop(struct dec_video *d_video, bool enabled); +void video_set_start(struct dec_video *d_video, double start_pts); + +#define VIDEO_OK 1 +#define VIDEO_WAIT 0 +#define VIDEO_EOF -1 +#define VIDEO_SKIP -2 +int video_get_frame(struct dec_video *d_video, struct mp_image **out_mpi); + struct demux_packet; struct mp_image *video_decode(struct dec_video *d_video, struct demux_packet *packet, int drop_frame); int video_vd_control(struct dec_video *d_video, int cmd, void *arg); -void video_reset_decoding(struct dec_video *d_video); +void video_reset(struct dec_video *d_video); void video_reset_aspect(struct dec_video *d_video); #endif /* MPLAYER_DEC_VIDEO_H */ -- cgit v1.2.3