diff options
Diffstat (limited to 'video')
87 files changed, 1683 insertions, 1163 deletions
diff --git a/video/csputils.c b/video/csputils.c index 08c484ffda..e446d8e724 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -7,23 +7,18 @@ * * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see <http://www.gnu.org/licenses/>. + * GNU Lesser General Public License for more details. * - * You can alternatively redistribute this file and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ #include "config.h" diff --git a/video/csputils.h b/video/csputils.h index 639011c588..d5990d242f 100644 --- a/video/csputils.h +++ b/video/csputils.h @@ -1,23 +1,18 @@ /* * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see <http://www.gnu.org/licenses/>. + * GNU Lesser General Public License for more details. * - * You can alternatively redistribute this file and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ #ifndef MPLAYER_CSPUTILS_H diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c index f28871c6bb..e8a57749ab 100644 --- a/video/decode/dec_video.c +++ b/video/decode/dec_video.c @@ -59,7 +59,6 @@ const vd_functions_t * const mpcodecs_vd_drivers[] = { void video_reset(struct dec_video *d_video) { video_vd_control(d_video, VDCTRL_RESET, NULL); - d_video->num_buffered_pts = 0; d_video->first_packet_pdts = MP_NOPTS_VALUE; d_video->start_pts = MP_NOPTS_VALUE; d_video->decoded_pts = MP_NOPTS_VALUE; @@ -67,8 +66,13 @@ void video_reset(struct dec_video *d_video) 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; + d_video->current_state = DATA_AGAIN; mp_image_unrefp(&d_video->current_mpi); + talloc_free(d_video->packet); + d_video->packet = NULL; + talloc_free(d_video->new_segment); + d_video->new_segment = NULL; + d_video->start = d_video->end = MP_NOPTS_VALUE; } int video_vd_control(struct dec_video *d_video, int cmd, void *arg) @@ -81,12 +85,16 @@ int video_vd_control(struct dec_video *d_video, int cmd, void *arg) void video_uninit(struct dec_video *d_video) { + if (!d_video) + return; 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"); d_video->vd_driver->uninit(d_video); } + talloc_free(d_video->packet); + talloc_free(d_video->new_segment); talloc_free(d_video); } @@ -125,15 +133,17 @@ static const struct vd_functions *find_driver(const char *name) return NULL; } -bool video_init_best_codec(struct dec_video *d_video, char* video_decoders) +bool video_init_best_codec(struct dec_video *d_video) { + struct MPOpts *opts = d_video->opts; + assert(!d_video->vd_driver); video_reset(d_video); d_video->has_broken_packet_pts = -10; // needs 10 packets to reach decision struct mp_decoder_entry *decoder = NULL; struct mp_decoder_list *list = - mp_select_video_decoders(d_video->header->codec->codec, video_decoders); + mp_select_video_decoders(d_video->codec->codec, opts->video_decoders); mp_print_decoders(d_video->log, MSGL_V, "Codec list:", list); @@ -161,7 +171,7 @@ bool video_init_best_codec(struct dec_video *d_video, char* video_decoders) MP_VERBOSE(d_video, "Selected video codec: %s\n", d_video->decoder_desc); } else { MP_ERR(d_video, "Failed to initialize a video decoder for codec '%s'.\n", - d_video->header->codec->codec); + d_video->codec->codec); } if (d_video->header->missing_timestamps) { @@ -179,7 +189,7 @@ static void fix_image_params(struct dec_video *d_video, { struct MPOpts *opts = d_video->opts; struct mp_image_params p = *params; - struct mp_codec_params *c = d_video->header->codec; + struct mp_codec_params *c = d_video->codec; MP_VERBOSE(d_video, "Decoder format: %s\n", mp_image_params_to_str(params)); @@ -233,73 +243,35 @@ static void fix_image_params(struct dec_video *d_video, d_video->fixed_format = p; } -static void add_avi_pts(struct dec_video *d_video, double pts) -{ - if (pts != MP_NOPTS_VALUE) { - int delay = -1; - video_vd_control(d_video, VDCTRL_QUERY_UNSEEN_FRAMES, &delay); - if (delay >= 0 && delay < d_video->num_buffered_pts) - d_video->num_buffered_pts = delay; - if (d_video->num_buffered_pts == MP_ARRAY_SIZE(d_video->buffered_pts)) { - MP_ERR(d_video, "Too many buffered pts\n"); - } else { - for (int i = d_video->num_buffered_pts; i > 0; i--) - d_video->buffered_pts[i] = d_video->buffered_pts[i - 1]; - d_video->buffered_pts[0] = pts; - d_video->num_buffered_pts++; - } - } -} - -static double retrieve_avi_pts(struct dec_video *d_video, double codec_pts) -{ - if (d_video->num_buffered_pts) { - d_video->num_buffered_pts--; - return d_video->buffered_pts[d_video->num_buffered_pts]; - } - MP_ERR(d_video, "No pts value from demuxer to use for frame!\n"); - return MP_NOPTS_VALUE; -} - 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; - struct demux_packet packet_copy; - if (packet && packet->dts == MP_NOPTS_VALUE) { - packet_copy = *packet; - packet = &packet_copy; - packet->dts = packet->pts; - } + if (!d_video->vd_driver) + return NULL; double pkt_pts = packet ? packet->pts : MP_NOPTS_VALUE; double pkt_dts = packet ? packet->dts : MP_NOPTS_VALUE; + if (pkt_pts == MP_NOPTS_VALUE) + d_video->has_broken_packet_pts = 1; + double pkt_pdts = pkt_pts == MP_NOPTS_VALUE ? pkt_dts : pkt_pts; if (pkt_pdts != MP_NOPTS_VALUE && d_video->first_packet_pdts == MP_NOPTS_VALUE) d_video->first_packet_pdts = pkt_pdts; - if (avi_pts) - add_avi_pts(d_video, pkt_pdts); - - double prev_codec_pts = d_video->codec_pts; - double prev_codec_dts = d_video->codec_dts; - - if (d_video->header->codec->avi_dts) - drop_frame = 0; - MP_STATS(d_video, "start decode video"); struct mp_image *mpi = d_video->vd_driver->decode(d_video, packet, drop_frame); MP_STATS(d_video, "end decode video"); + // Error, discarded frame, dropped frame, or initial codec delay. if (!mpi || drop_frame) { talloc_free(mpi); - return NULL; // error / skipped frame + return NULL; } if (opts->field_dominance == 0) { @@ -310,30 +282,31 @@ static struct mp_image *decode_packet(struct dec_video *d_video, } // Note: the PTS is reordered, but the DTS is not. Both should be monotonic. - double pts = d_video->codec_pts; - double dts = d_video->codec_dts; + double pts = mpi->pts; + double dts = mpi->dts; - if (pts == MP_NOPTS_VALUE) { - d_video->codec_pts = prev_codec_pts; - } else if (pts < prev_codec_pts) { - d_video->num_codec_pts_problems++; + if (pts != MP_NOPTS_VALUE) { + if (pts < d_video->codec_pts) + d_video->num_codec_pts_problems++; + d_video->codec_pts = mpi->pts; } - if (dts == MP_NOPTS_VALUE) { - d_video->codec_dts = prev_codec_dts; - } else if (dts <= prev_codec_dts) { - d_video->num_codec_dts_problems++; + if (dts != MP_NOPTS_VALUE) { + if (dts <= d_video->codec_dts) + d_video->num_codec_dts_problems++; + d_video->codec_dts = mpi->dts; } + if (d_video->has_broken_packet_pts < 0) + d_video->has_broken_packet_pts++; + if (d_video->num_codec_pts_problems) + d_video->has_broken_packet_pts = 1; + // If PTS is unset, or non-monotonic, fall back to DTS. if ((d_video->num_codec_pts_problems > d_video->num_codec_dts_problems || pts == MP_NOPTS_VALUE) && dts != MP_NOPTS_VALUE) pts = dts; - // Alternative PTS determination methods - if (avi_pts) - pts = retrieve_avi_pts(d_video, pts); - if (!opts->correct_pts || pts == MP_NOPTS_VALUE) { if (opts->correct_pts && !d_video->header->missing_timestamps) MP_WARN(d_video, "No video PTS! Making something up.\n"); @@ -348,11 +321,6 @@ static struct mp_image *decode_packet(struct dec_video *d_video, } } - if (d_video->has_broken_packet_pts < 0) - d_video->has_broken_packet_pts++; - if (d_video->num_codec_pts_problems || pkt_pts == MP_NOPTS_VALUE) - d_video->has_broken_packet_pts = 1; - if (!mp_image_params_equal(&d_video->last_format, &mpi->params)) fix_image_params(d_video, &mpi->params); @@ -360,6 +328,16 @@ static struct mp_image *decode_packet(struct dec_video *d_video, mpi->pts = pts; d_video->decoded_pts = pts; + + // Compensate for incorrectly using mpeg-style DTS for avi timestamps. + if (d_video->codec->avi_dts && opts->correct_pts && + mpi->pts != MP_NOPTS_VALUE && d_video->fps > 0) + { + int delay = -1; + video_vd_control(d_video, VDCTRL_GET_BFRAMES, &delay); + mpi->pts -= MPMAX(delay, 0) / d_video->fps; + } + return mpi; } @@ -385,63 +363,119 @@ void video_work(struct dec_video *d_video) return; if (d_video->header->attached_picture) { - if (d_video->current_state == VIDEO_SKIP && !d_video->cover_art_mpi) { + if (d_video->current_state == DATA_AGAIN && !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; + d_video->current_state = DATA_OK; } - if (d_video->current_state == VIDEO_OK) + if (d_video->current_state == DATA_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; + // (DATA_OK is returned the first time, when current_mpi is sill set) + d_video->current_state = DATA_EOF; return; } - struct demux_packet *pkt; - if (demux_read_packet_async(d_video->header, &pkt) == 0) { - d_video->current_state = VIDEO_WAIT; + if (!d_video->packet && !d_video->new_segment && + demux_read_packet_async(d_video->header, &d_video->packet) == 0) + { + d_video->current_state = DATA_WAIT; return; } + if (d_video->packet) { + if (d_video->packet->dts == MP_NOPTS_VALUE && !d_video->codec->avi_dts) + d_video->packet->dts = d_video->packet->pts; + } + + if (d_video->packet && d_video->packet->new_segment) { + assert(!d_video->new_segment); + d_video->new_segment = d_video->packet; + d_video->packet = NULL; + } + + bool had_input_packet = !!d_video->packet; + bool had_packet = had_input_packet || d_video->new_segment; + + double start_pts = d_video->st |