X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=input%2Fffms.c;h=6a3eb6c7663aba9a0d2901ce17e1a31d840de164;hb=b08403b5593307b919bfe5bfbd743da825326a4c;hp=08ac21f1cddf5f42b771e3aa6aa6050a643cdbda;hpb=b3005ee3fe778d4eade4d472ee9550120040caee;p=x264 diff --git a/input/ffms.c b/input/ffms.c index 08ac21f1..6a3eb6c7 100644 --- a/input/ffms.c +++ b/input/ffms.c @@ -1,10 +1,11 @@ /***************************************************************************** - * ffms.c: x264 ffmpegsource input module + * ffms.c: ffmpegsource input ***************************************************************************** - * Copyright (C) 2009 x264 project + * Copyright (C) 2009-2015 x264 project * * Authors: Mike Gurlitz * Steven Walters + * Henrik Gramner * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,123 +20,137 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. *****************************************************************************/ -#include "muxers.h" +#include "input.h" #include +#define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "ffms", __VA_ARGS__ ) + #undef DECLARE_ALIGNED #include #include #ifdef _WIN32 #include -#else -#define SetConsoleTitle(t) #endif typedef struct { FFMS_VideoSource *video_source; FFMS_Track *track; - int total_frames; - struct SwsContext *scaler; - int pts_offset_flag; - int64_t pts_offset; int reduce_pts; int vfr_input; - - int init_width; - int init_height; - - int cur_width; - int cur_height; - int cur_pix_fmt; + int num_frames; + int64_t time; } ffms_hnd_t; static int FFMS_CC update_progress( int64_t current, int64_t total, void *private ) { - if( current % 10 ) + int64_t *update_time = private; + int64_t oldtime = *update_time; + int64_t newtime = x264_mdate(); + if( oldtime && newtime - oldtime < UPDATE_INTERVAL ) return 0; + *update_time = newtime; + char buf[200]; sprintf( buf, "ffms [info]: indexing input file [%.1f%%]", 100.0 * current / total ); fprintf( stderr, "%s \r", buf+5 ); - SetConsoleTitle( buf ); + x264_cli_set_console_title( buf ); fflush( stderr ); return 0; } +/* handle the deprecated jpeg pixel formats */ +static int handle_jpeg( int csp, int *fullrange ) +{ + switch( csp ) + { + case AV_PIX_FMT_YUVJ420P: *fullrange = 1; return AV_PIX_FMT_YUV420P; + case AV_PIX_FMT_YUVJ422P: *fullrange = 1; return AV_PIX_FMT_YUV422P; + case AV_PIX_FMT_YUVJ444P: *fullrange = 1; return AV_PIX_FMT_YUV444P; + default: return csp; + } +} + static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt ) { ffms_hnd_t *h = calloc( 1, sizeof(ffms_hnd_t) ); if( !h ) return -1; - FFMS_Init( 0 ); + +#ifdef __MINGW32__ + /* FFMS supports UTF-8 filenames, but it uses std::fstream internally which is broken with Unicode in MinGW. */ + FFMS_Init( 0, 0 ); + char src_filename[MAX_PATH]; + char idx_filename[MAX_PATH]; + FAIL_IF_ERROR( !x264_ansi_filename( psz_filename, src_filename, MAX_PATH, 0 ), "invalid ansi filename\n" ); + if( opt->index_file ) + FAIL_IF_ERROR( !x264_ansi_filename( opt->index_file, idx_filename, MAX_PATH, 1 ), "invalid ansi filename\n" ); +#else + FFMS_Init( 0, 1 ); + char *src_filename = psz_filename; + char *idx_filename = opt->index_file; +#endif + FFMS_ErrorInfo e; e.BufferSize = 0; int seekmode = opt->seek ? FFMS_SEEK_NORMAL : FFMS_SEEK_LINEAR_NO_RW; - FFMS_Index *index = NULL; - if( opt->index ) + FFMS_Index *idx = NULL; + if( opt->index_file ) { - struct stat index_s, input_s; - if( !stat( opt->index, &index_s ) && !stat( psz_filename, &input_s ) && - input_s.st_mtime < index_s.st_mtime ) - index = FFMS_ReadIndex( opt->index, &e ); + x264_struct_stat index_s, input_s; + if( !x264_stat( opt->index_file, &index_s ) && !x264_stat( psz_filename, &input_s ) && + input_s.st_mtime < index_s.st_mtime && index_s.st_size ) + idx = FFMS_ReadIndex( idx_filename, &e ); } - if( !index ) + if( !idx ) { - index = FFMS_MakeIndex( psz_filename, 0, 0, NULL, NULL, 0, update_progress, NULL, &e ); - fprintf( stderr, " \r" ); - if( !index ) + if( opt->progress ) { - fprintf( stderr, "ffms [error]: could not create index\n" ); - return -1; + idx = FFMS_MakeIndex( src_filename, 0, 0, NULL, NULL, 0, update_progress, &h->time, &e ); + fprintf( stderr, " \r" ); } - if( opt->index && FFMS_WriteIndex( opt->index, index, &e ) ) - fprintf( stderr, "ffms [warning]: could not write index file\n" ); + else + idx = FFMS_MakeIndex( src_filename, 0, 0, NULL, NULL, 0, NULL, NULL, &e ); + FAIL_IF_ERROR( !idx, "could not create index\n" ) + if( opt->index_file && FFMS_WriteIndex( idx_filename, idx, &e ) ) + x264_cli_log( "ffms", X264_LOG_WARNING, "could not write index file\n" ); } - int trackno = FFMS_GetFirstTrackOfType( index, FFMS_TYPE_VIDEO, &e ); - if( trackno < 0 ) - { - fprintf( stderr, "ffms [error]: could not find video track\n" ); - return -1; - } + int trackno = FFMS_GetFirstTrackOfType( idx, FFMS_TYPE_VIDEO, &e ); + FAIL_IF_ERROR( trackno < 0, "could not find video track\n" ) - h->video_source = FFMS_CreateVideoSource( psz_filename, trackno, index, 1, seekmode, &e ); - if( !h->video_source ) - { - fprintf( stderr, "ffms [error]: could not create video source\n" ); - return -1; - } + h->video_source = FFMS_CreateVideoSource( src_filename, trackno, idx, 1, seekmode, &e ); + FAIL_IF_ERROR( !h->video_source, "could not create video source\n" ) h->track = FFMS_GetTrackFromVideo( h->video_source ); - FFMS_DestroyIndex( index ); + FFMS_DestroyIndex( idx ); const FFMS_VideoProperties *videop = FFMS_GetVideoProperties( h->video_source ); - h->total_frames = videop->NumFrames; + info->num_frames = h->num_frames = videop->NumFrames; info->sar_height = videop->SARDen; info->sar_width = videop->SARNum; info->fps_den = videop->FPSDenominator; info->fps_num = videop->FPSNumerator; h->vfr_input = info->vfr; + /* ffms is thread unsafe as it uses a single frame buffer for all frame requests */ + info->thread_safe = 0; const FFMS_Frame *frame = FFMS_GetFrame( h->video_source, 0, &e ); - if( !frame ) - { - fprintf( stderr, "ffms [error]: could not read frame 0\n" ); - return -1; - } + FAIL_IF_ERROR( !frame, "could not read frame 0\n" ) - h->init_width = h->cur_width = info->width = frame->EncodedWidth; - h->init_height = h->cur_height = info->height = frame->EncodedHeight; - h->cur_pix_fmt = frame->EncodedPixelFormat; + info->fullrange = 0; + info->width = frame->EncodedWidth; + info->height = frame->EncodedHeight; + info->csp = handle_jpeg( frame->EncodedPixelFormat, &info->fullrange ) | X264_CSP_OTHER; info->interlaced = frame->InterlacedFrame; info->tff = frame->TopFieldFirst; - - if( h->cur_pix_fmt != PIX_FMT_YUV420P ) - fprintf( stderr, "ffms [warning]: converting from %s to YV12\n", - avcodec_get_pix_fmt_name( h->cur_pix_fmt ) ); + info->fullrange |= frame->ColorRange == FFMS_CR_JPEG; /* ffms timestamps are in milliseconds. ffms also uses int64_ts for timebase, * so we need to reduce large timebases to prevent overflow */ @@ -160,85 +175,51 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c return 0; } -static int get_frame_total( hnd_t handle ) -{ - return ((ffms_hnd_t*)handle)->total_frames; -} - -static int check_swscale( ffms_hnd_t *h, const FFMS_Frame *frame, int i_frame ) +static int picture_alloc( cli_pic_t *pic, int csp, int width, int height ) { - if( h->scaler && h->cur_width == frame->EncodedWidth && h->cur_height == frame->EncodedHeight && - h->cur_pix_fmt == frame->EncodedPixelFormat ) - return 0; - if( h->scaler ) - { - sws_freeContext( h->scaler ); - fprintf( stderr, "ffms [warning]: stream properties changed to %dx%d, %s at frame %d \n", frame->EncodedWidth, - frame->EncodedHeight, avcodec_get_pix_fmt_name( frame->EncodedPixelFormat ), i_frame ); - h->cur_width = frame->EncodedWidth; - h->cur_height = frame->EncodedHeight; - h->cur_pix_fmt = frame->EncodedPixelFormat; - } - h->scaler = sws_getContext( h->cur_width, h->cur_height, h->cur_pix_fmt, h->init_width, h->init_height, - PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL ); - if( !h->scaler ) - { - fprintf( stderr, "ffms [error]: could not open swscale context\n" ); + if( x264_cli_pic_alloc( pic, X264_CSP_NONE, width, height ) ) return -1; - } + pic->img.csp = csp; + pic->img.planes = 4; return 0; } -static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame ) +static int read_frame( cli_pic_t *pic, hnd_t handle, int i_frame ) { ffms_hnd_t *h = handle; + if( i_frame >= h->num_frames ) + return -1; FFMS_ErrorInfo e; e.BufferSize = 0; const FFMS_Frame *frame = FFMS_GetFrame( h->video_source, i_frame, &e ); - if( !frame ) - { - fprintf( stderr, "ffms [error]: could not read frame %d\n", i_frame ); - return -1; - } - - if( check_swscale( h, frame, i_frame ) ) - return -1; - /* FFMS_VideoSource has a single FFMS_Frame buffer for all calls to GetFrame. - * With threaded input, copying the pointers would result in the data changing during encoding. - * FIXME: don't do redundant sws_scales for singlethreaded input, or fix FFMS to allow - * multiple FFMS_Frame buffers. */ - sws_scale( h->scaler, (uint8_t**)frame->Data, (int*)frame->Linesize, 0, - frame->EncodedHeight, p_pic->img.plane, p_pic->img.i_stride ); + FAIL_IF_ERROR( !frame, "could not read frame %d \n", i_frame ) - const FFMS_FrameInfo *info = FFMS_GetFrameInfo( h->track, i_frame ); + memcpy( pic->img.stride, frame->Linesize, sizeof(pic->img.stride) ); + memcpy( pic->img.plane, frame->Data, sizeof(pic->img.plane) ); if( h->vfr_input ) { - if( info->PTS == AV_NOPTS_VALUE ) - { - fprintf( stderr, "ffms [error]: invalid timestamp. " - "Use --force-cfr and specify a framerate with --fps\n" ); - return -1; - } + const FFMS_FrameInfo *info = FFMS_GetFrameInfo( h->track, i_frame ); + FAIL_IF_ERROR( info->PTS == AV_NOPTS_VALUE, "invalid timestamp. " + "Use --force-cfr and specify a framerate with --fps\n" ) - if( !h->pts_offset_flag ) - { - h->pts_offset = info->PTS; - h->pts_offset_flag = 1; - } - - p_pic->i_pts = (info->PTS - h->pts_offset) >> h->reduce_pts; + pic->pts = info->PTS >> h->reduce_pts; + pic->duration = 0; } return 0; } +static void picture_clean( cli_pic_t *pic ) +{ + memset( pic, 0, sizeof(cli_pic_t) ); +} + static int close_file( hnd_t handle ) { ffms_hnd_t *h = handle; - sws_freeContext( h->scaler ); FFMS_DestroyVideoSource( h->video_source ); free( h ); return 0; } -const cli_input_t ffms_input = { open_file, get_frame_total, x264_picture_alloc, read_frame, NULL, x264_picture_clean, close_file }; +const cli_input_t ffms_input = { open_file, picture_alloc, read_frame, NULL, picture_clean, close_file };