1 /*****************************************************************************
2 * ffms.c: x264 ffmpegsource input module
3 *****************************************************************************
4 * Copyright (C) 2009 x264 project
6 * Authors: Mike Gurlitz <mike.gurlitz@gmail.com>
7 * Steven Walters <kemuri9@gmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
22 *****************************************************************************/
26 #undef DECLARE_ALIGNED
27 #include <libavcodec/avcodec.h>
28 #include <libswscale/swscale.h>
33 #define SetConsoleTitle(t)
38 FFMS_VideoSource *video_source;
41 struct SwsContext *scaler;
55 static int FFMS_CC update_progress( int64_t current, int64_t total, void *private )
60 sprintf( buf, "ffms [info]: indexing input file [%.1f%%]", 100.0 * current / total );
61 fprintf( stderr, "%s \r", buf+5 );
62 SetConsoleTitle( buf );
67 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
69 ffms_hnd_t *h = calloc( 1, sizeof(ffms_hnd_t) );
75 int seekmode = opt->seek ? FFMS_SEEK_NORMAL : FFMS_SEEK_LINEAR_NO_RW;
77 FFMS_Index *index = NULL;
80 struct stat index_s, input_s;
81 if( !stat( opt->index, &index_s ) && !stat( psz_filename, &input_s ) &&
82 input_s.st_mtime < index_s.st_mtime )
83 index = FFMS_ReadIndex( opt->index, &e );
87 index = FFMS_MakeIndex( psz_filename, 0, 0, NULL, NULL, 0, update_progress, NULL, &e );
88 fprintf( stderr, " \r" );
91 fprintf( stderr, "ffms [error]: could not create index\n" );
94 if( opt->index && FFMS_WriteIndex( opt->index, index, &e ) )
95 fprintf( stderr, "ffms [warning]: could not write index file\n" );
98 int trackno = FFMS_GetFirstTrackOfType( index, FFMS_TYPE_VIDEO, &e );
101 fprintf( stderr, "ffms [error]: could not find video track\n" );
105 h->video_source = FFMS_CreateVideoSource( psz_filename, trackno, index, 1, seekmode, &e );
106 if( !h->video_source )
108 fprintf( stderr, "ffms [error]: could not create video source\n" );
112 h->track = FFMS_GetTrackFromVideo( h->video_source );
113 const FFMS_TrackTimeBase *timebase = FFMS_GetTimeBase( h->track );
115 FFMS_DestroyIndex( index );
116 const FFMS_VideoProperties *videop = FFMS_GetVideoProperties( h->video_source );
117 h->total_frames = videop->NumFrames;
118 info->sar_height = videop->SARDen;
119 info->sar_width = videop->SARNum;
120 info->fps_den = videop->FPSDenominator;
121 info->fps_num = videop->FPSNumerator;
122 info->timebase_num = (int)timebase->Num;
123 h->vfr_input = info->vfr;
125 const FFMS_Frame *frame = FFMS_GetFrame( h->video_source, 0, &e );
128 fprintf( stderr, "ffms [error]: could not read frame 0\n" );
132 h->init_width = h->cur_width = info->width = frame->EncodedWidth;
133 h->init_height = h->cur_height = info->height = frame->EncodedHeight;
134 h->cur_pix_fmt = frame->EncodedPixelFormat;
135 info->interlaced = frame->InterlacedFrame;
137 if( h->cur_pix_fmt != PIX_FMT_YUV420P )
138 fprintf( stderr, "ffms [warning]: converting from %s to YV12\n",
139 avcodec_get_pix_fmt_name( h->cur_pix_fmt ) );
141 /* ffms timestamps are in milliseconds. Increasing timebase denominator could cause integer overflow.
142 * Conversely, reducing PTS may lose too much accuracy */
145 int64_t timebase_den = (int64_t)timebase->Den * 1000;
147 if( timebase_den > INT_MAX )
149 info->timebase_den = (int)timebase->Den;
154 info->timebase_den = (int)timebase->Den * 1000;
163 static int get_frame_total( hnd_t handle )
165 return ((ffms_hnd_t*)handle)->total_frames;
168 static int check_swscale( ffms_hnd_t *h, const FFMS_Frame *frame, int i_frame )
170 if( h->scaler && h->cur_width == frame->EncodedWidth && h->cur_height == frame->EncodedHeight &&
171 h->cur_pix_fmt == frame->EncodedPixelFormat )
175 sws_freeContext( h->scaler );
176 fprintf( stderr, "ffms [warning]: stream properties changed to %dx%d, %s at frame %d \n", frame->EncodedWidth,
177 frame->EncodedHeight, avcodec_get_pix_fmt_name( frame->EncodedPixelFormat ), i_frame );
178 h->cur_width = frame->EncodedWidth;
179 h->cur_height = frame->EncodedHeight;
180 h->cur_pix_fmt = frame->EncodedPixelFormat;
182 h->scaler = sws_getContext( h->cur_width, h->cur_height, h->cur_pix_fmt, h->init_width, h->init_height,
183 PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL );
186 fprintf( stderr, "ffms [error]: could not open swscale context\n" );
192 static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
194 ffms_hnd_t *h = handle;
197 const FFMS_Frame *frame = FFMS_GetFrame( h->video_source, i_frame, &e );
200 fprintf( stderr, "ffms [error]: could not read frame %d\n", i_frame );
204 if( check_swscale( h, frame, i_frame ) )
206 /* FFMS_VideoSource has a single FFMS_Frame buffer for all calls to GetFrame.
207 * With threaded input, copying the pointers would result in the data changing during encoding.
208 * FIXME: don't do redundant sws_scales for singlethreaded input, or fix FFMS to allow
209 * multiple FFMS_Frame buffers. */
210 sws_scale( h->scaler, (uint8_t**)frame->Data, (int*)frame->Linesize, 0,
211 frame->EncodedHeight, p_pic->img.plane, p_pic->img.i_stride );
213 const FFMS_FrameInfo *info = FFMS_GetFrameInfo( h->track, i_frame );
217 if( info->PTS == AV_NOPTS_VALUE )
219 fprintf( stderr, "ffms [error]: invalid timestamp. "
220 "Use --force-cfr and specify a framerate with --fps\n" );
224 if( !h->pts_offset_flag )
226 h->pts_offset = info->PTS;
227 h->pts_offset_flag = 1;
231 p_pic->i_pts = (int64_t)(((info->PTS - h->pts_offset) / 1000) + 0.5);
233 p_pic->i_pts = info->PTS - h->pts_offset;
238 static int close_file( hnd_t handle )
240 ffms_hnd_t *h = handle;
241 sws_freeContext( h->scaler );
242 FFMS_DestroyVideoSource( h->video_source );
247 const cli_input_t ffms_input = { open_file, get_frame_total, x264_picture_alloc, read_frame, NULL, x264_picture_clean, close_file };