/*****************************************************************************1* fix_vfr_pts.c: vfr pts fixing video filter2*****************************************************************************3* Copyright (C) 2010-2016 x264 project4*5* Authors: Steven Walters <[email protected]>6*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License as published by9* the Free Software Foundation; either version 2 of the License, or10* (at your option) any later version.11*12* This program is distributed in the hope that it will be useful,13* but WITHOUT ANY WARRANTY; without even the implied warranty of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15* GNU General Public License for more details.16*17* You should have received a copy of the GNU General Public License18* along with this program; if not, write to the Free Software19* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.20*21* This program is also available under a commercial proprietary license.22* For more information, contact us at [email protected].23*****************************************************************************/2425#include "video.h"26#include "internal.h"2728/* This filter calculates and store the frame's duration to the frame data29* (if it is not already calculated when the frame arrives to this point)30* so it can be used by filters that will need to reconstruct pts due to31* out-of-order frame requests */3233typedef struct34{35hnd_t prev_hnd;36cli_vid_filter_t prev_filter;3738/* we need 1 buffer picture and 1 place holder */39cli_pic_t buffer;40cli_pic_t holder;41int buffer_allocated;42int holder_frame;43int holder_ret;44int64_t pts;45int64_t last_duration;46} fix_vfr_pts_hnd_t;4748cli_vid_filter_t fix_vfr_pts_filter;4950static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string )51{52/* if the input is not vfr, we don't do anything */53if( !info->vfr )54return 0;55fix_vfr_pts_hnd_t *h = calloc( 1, sizeof(fix_vfr_pts_hnd_t) );56if( !h )57return -1;5859h->holder_frame = -1;60h->prev_hnd = *handle;61h->prev_filter = *filter;62*handle = h;63*filter = fix_vfr_pts_filter;6465return 0;66}6768static int get_frame( hnd_t handle, cli_pic_t *output, int frame )69{70fix_vfr_pts_hnd_t *h = handle;71/* if we want the holder picture and it errored, return the error. */72if( frame == h->holder_frame )73{74if( h->holder_ret )75return h->holder_ret;76}77else78{79/* if we have a holder frame and we don't want it, release the frame */80if( h->holder_frame > 0 && h->holder_frame < frame && h->prev_filter.release_frame( h->prev_hnd, &h->holder, h->holder_frame ) )81return -1;82h->holder_frame = -1;83if( h->prev_filter.get_frame( h->prev_hnd, &h->holder, frame ) )84return -1;85}8687/* if the frame's duration is not set already, read the next frame to set it. */88if( !h->holder.duration )89{90/* allocate a buffer picture if we didn't already */91if( !h->buffer_allocated )92{93if( x264_cli_pic_alloc( &h->buffer, h->holder.img.csp, h->holder.img.width, h->holder.img.height ) )94return -1;95h->buffer_allocated = 1;96}97h->holder_frame = frame+1;98/* copy the current frame to the buffer, release it, and then read in the next frame to the placeholder */99if( x264_cli_pic_copy( &h->buffer, &h->holder ) || h->prev_filter.release_frame( h->prev_hnd, &h->holder, frame ) )100return -1;101h->holder_ret = h->prev_filter.get_frame( h->prev_hnd, &h->holder, h->holder_frame );102/* suppress non-monotonic pts warnings by setting the duration to be at least 1 */103if( !h->holder_ret )104h->last_duration = X264_MAX( h->holder.pts - h->buffer.pts, 1 );105h->buffer.duration = h->last_duration;106*output = h->buffer;107}108else109*output = h->holder;110111output->pts = h->pts;112h->pts += output->duration;113114return 0;115}116117static int release_frame( hnd_t handle, cli_pic_t *pic, int frame )118{119fix_vfr_pts_hnd_t *h = handle;120/* if the frame is the buffered one, it's already been released */121if( frame == (h->holder_frame - 1) )122return 0;123return h->prev_filter.release_frame( h->prev_hnd, pic, frame );124}125126static void free_filter( hnd_t handle )127{128fix_vfr_pts_hnd_t *h = handle;129h->prev_filter.free( h->prev_hnd );130if( h->buffer_allocated )131x264_cli_pic_clean( &h->buffer );132free( h );133}134135cli_vid_filter_t fix_vfr_pts_filter = { "fix_vfr_pts", NULL, init, get_frame, release_frame, free_filter, NULL };136137138