1 /*****************************************************************************
2 * ffms.c: ffmpegsource input
3 *****************************************************************************
4 * Copyright (C) 2009-2017 x264 project
6 * Authors: Mike Gurlitz <mike.gurlitz@gmail.com>
7 * Steven Walters <kemuri9@gmail.com>
8 * Henrik Gramner <henrik@gramner.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
24 * This program is also available under a commercial proprietary license.
25 * For more information, contact us at licensing@x264.com.
26 *****************************************************************************/
30 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "ffms", __VA_ARGS__ )
32 #undef DECLARE_ALIGNED
33 #include <libavcodec/avcodec.h>
34 #include <libswscale/swscale.h>
35 #include <libavutil/pixdesc.h>
37 #define PROGRESS_LENGTH 36
41 FFMS_VideoSource
*video_source
;
49 static int FFMS_CC
update_progress( int64_t current
, int64_t total
, void *private )
51 int64_t *update_time
= private;
52 int64_t oldtime
= *update_time
;
53 int64_t newtime
= x264_mdate();
54 if( oldtime
&& newtime
- oldtime
< UPDATE_INTERVAL
)
56 *update_time
= newtime
;
58 char buf
[PROGRESS_LENGTH
+5+1];
59 snprintf( buf
, sizeof(buf
), "ffms [info]: indexing input file [%.1f%%]", 100.0 * current
/ total
);
60 fprintf( stderr
, "%-*s\r", PROGRESS_LENGTH
, buf
+5 );
61 x264_cli_set_console_title( buf
);
66 /* handle the deprecated jpeg pixel formats */
67 static int handle_jpeg( int csp
, int *fullrange
)
71 case AV_PIX_FMT_YUVJ420P
: *fullrange
= 1; return AV_PIX_FMT_YUV420P
;
72 case AV_PIX_FMT_YUVJ422P
: *fullrange
= 1; return AV_PIX_FMT_YUV422P
;
73 case AV_PIX_FMT_YUVJ444P
: *fullrange
= 1; return AV_PIX_FMT_YUV444P
;
78 static int open_file( char *psz_filename
, hnd_t
*p_handle
, video_info_t
*info
, cli_input_opt_t
*opt
)
80 ffms_hnd_t
*h
= calloc( 1, sizeof(ffms_hnd_t
) );
87 int seekmode
= opt
->seek
? FFMS_SEEK_NORMAL
: FFMS_SEEK_LINEAR_NO_RW
;
89 FFMS_Index
*idx
= NULL
;
92 x264_struct_stat index_s
, input_s
;
93 if( !x264_stat( opt
->index_file
, &index_s
) && !x264_stat( psz_filename
, &input_s
) && input_s
.st_mtime
< index_s
.st_mtime
)
95 idx
= FFMS_ReadIndex( opt
->index_file
, &e
);
96 if( idx
&& FFMS_IndexBelongsToFile( idx
, psz_filename
, &e
) )
98 FFMS_DestroyIndex( idx
);
105 FFMS_Indexer
*indexer
= FFMS_CreateIndexer( psz_filename
, &e
);
106 FAIL_IF_ERROR( !indexer
, "could not create indexer\n" );
109 FFMS_SetProgressCallback( indexer
, update_progress
, &h
->time
);
111 idx
= FFMS_DoIndexing2( indexer
, FFMS_IEH_ABORT
, &e
);
112 fprintf( stderr
, "%*c", PROGRESS_LENGTH
+1, '\r' );
113 FAIL_IF_ERROR( !idx
, "could not create index\n" );
115 if( opt
->index_file
&& FFMS_WriteIndex( opt
->index_file
, idx
, &e
) )
116 x264_cli_log( "ffms", X264_LOG_WARNING
, "could not write index file\n" );
119 int trackno
= FFMS_GetFirstTrackOfType( idx
, FFMS_TYPE_VIDEO
, &e
);
121 h
->video_source
= FFMS_CreateVideoSource( psz_filename
, trackno
, idx
, opt
->demuxer_threads
, seekmode
, &e
);
122 FFMS_DestroyIndex( idx
);
124 FAIL_IF_ERROR( trackno
< 0, "could not find video track\n" );
125 FAIL_IF_ERROR( !h
->video_source
, "could not create video source\n" );
127 const FFMS_VideoProperties
*videop
= FFMS_GetVideoProperties( h
->video_source
);
128 info
->num_frames
= h
->num_frames
= videop
->NumFrames
;
129 info
->sar_height
= videop
->SARDen
;
130 info
->sar_width
= videop
->SARNum
;
131 info
->fps_den
= videop
->FPSDenominator
;
132 info
->fps_num
= videop
->FPSNumerator
;
133 h
->vfr_input
= info
->vfr
;
134 /* ffms is thread unsafe as it uses a single frame buffer for all frame requests */
135 info
->thread_safe
= 0;
137 if( !opt
->b_accurate_fps
)
138 x264_ntsc_fps( &info
->fps_num
, &info
->fps_den
);
140 const FFMS_Frame
*frame
= FFMS_GetFrame( h
->video_source
, 0, &e
);
141 FAIL_IF_ERROR( !frame
, "could not read frame 0\n" );
143 /* -1 = 'unset' (internal) , 2 from lavf|ffms = 'unset' */
144 if( frame
->ColorSpace
>= 0 && frame
->ColorSpace
<= 8 && frame
->ColorSpace
!= 2 )
145 info
->colormatrix
= frame
->ColorSpace
;
147 info
->colormatrix
= -1;
150 info
->width
= frame
->EncodedWidth
;
151 info
->height
= frame
->EncodedHeight
;
152 info
->csp
= handle_jpeg( frame
->EncodedPixelFormat
, &info
->fullrange
) | X264_CSP_OTHER
;
153 info
->interlaced
= frame
->InterlacedFrame
;
154 info
->tff
= frame
->TopFieldFirst
;
155 info
->fullrange
|= frame
->ColorRange
== FFMS_CR_JPEG
;
157 /* ffms timestamps are in milliseconds. ffms also uses int64_ts for timebase,
158 * so we need to reduce large timebases to prevent overflow */
159 h
->track
= FFMS_GetTrackFromVideo( h
->video_source
);
160 const FFMS_TrackTimeBase
*timebase
= FFMS_GetTimeBase( h
->track
);
163 int64_t timebase_num
= timebase
->Num
;
164 int64_t timebase_den
= timebase
->Den
* 1000;
167 while( timebase_num
> UINT32_MAX
|| timebase_den
> INT32_MAX
)
173 info
->timebase_num
= timebase_num
;
174 info
->timebase_den
= timebase_den
;
177 /* show video info */
178 FFMS_Indexer
*idxer
= FFMS_CreateIndexer( psz_filename
, &e
);
179 const char *format
= FFMS_GetFormatNameI( idxer
);
180 const char *codec
= FFMS_GetCodecNameI( idxer
, trackno
);
181 double duration
= videop
->NumFrames
* videop
->FPSDenominator
/ videop
->FPSNumerator
;
182 x264_cli_log( "ffms", X264_LOG_INFO
,
186 "\n Framerate : %d/%d"
187 "\n Timebase : %"PRIu64
"/%"PRIu64
188 "\n Duration : %d:%02d:%02d\n",
191 av_pix_fmt_desc_get(frame
->EncodedPixelFormat
)->name
,
192 videop
->FPSNumerator
, videop
->FPSDenominator
,
193 (uint64_t)timebase
->Num
, (uint64_t)timebase
->Den
* 1000,
194 (int)duration
/ 60 / 60, (int)duration
/ 60 % 60, (int)duration
- (int)duration
/ 60 * 60 );
195 if( !strcmp( codec
,"rawvideo" ) )
196 x264_cli_log( "ffms", X264_LOG_WARNING
, "recommend using --demuxer lavf with rawvideo" );
197 FFMS_CancelIndexing( idxer
);
203 static int picture_alloc( cli_pic_t
*pic
, hnd_t handle
, int csp
, int width
, int height
)
205 if( x264_cli_pic_alloc( pic
, X264_CSP_NONE
, width
, height
) )
212 static int read_frame( cli_pic_t
*pic
, hnd_t handle
, int i_frame
)
214 ffms_hnd_t
*h
= handle
;
215 if( i_frame
>= h
->num_frames
)
219 const FFMS_Frame
*frame
= FFMS_GetFrame( h
->video_source
, i_frame
, &e
);
220 FAIL_IF_ERROR( !frame
, "could not read frame %d \n", i_frame
);
222 memcpy( pic
->img
.stride
, frame
->Linesize
, sizeof(pic
->img
.stride
) );
223 memcpy( pic
->img
.plane
, frame
->Data
, sizeof(pic
->img
.plane
) );
227 const FFMS_FrameInfo
*info
= FFMS_GetFrameInfo( h
->track
, i_frame
);
228 FAIL_IF_ERROR( info
->PTS
== AV_NOPTS_VALUE
, "invalid timestamp. "
229 "Use --force-cfr and specify a framerate with --fps\n" );
231 pic
->pts
= info
->PTS
>> h
->reduce_pts
;
237 static void picture_clean( cli_pic_t
*pic
, hnd_t handle
)
239 memset( pic
, 0, sizeof(cli_pic_t
) );
242 static int close_file( hnd_t handle
)
244 ffms_hnd_t
*h
= handle
;
245 FFMS_DestroyVideoSource( h
->video_source
);
250 const cli_input_t ffms_input
= { open_file
, picture_alloc
, read_frame
, NULL
, picture_clean
, close_file
};