encoder/set.c encoder/macroblock.c encoder/cabac.c \
encoder/cavlc.c encoder/encoder.c encoder/lookahead.c
-SRCCLI = x264.c matroska.c muxers.c
+SRCCLI = x264.c input/yuv.c input/y4m.c output/raw.c \
+ output/matroska.c output/matroska_ebml.c
+
+MUXERS := $(shell grep -E "(IN|OUT)PUT" config.h)
+
+# Optional muxer module sources
+ifneq ($(findstring AVIS_INPUT, $(MUXERS)),)
+SRCCLI += input/avis.c
+endif
+
+ifneq ($(findstring HAVE_PTHREAD, $(CFLAGS)),)
+SRCCLI += input/thread.c
+endif
+
+ifneq ($(findstring MP4_OUTPUT, $(MUXERS)),)
+SRCCLI += output/mp4.c
+endif
# Visualization sources
ifeq ($(VIS),yes)
--- /dev/null
+/*****************************************************************************
+ * avis.c: x264 avi/avs input module
+ *****************************************************************************
+ * Copyright (C) 2003-2009 x264 project
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * Loren Merritt <lorenm@u.washington.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#include "muxers.h"
+#include <windows.h>
+#include <vfw.h>
+
+typedef struct
+{
+ PAVISTREAM p_avi;
+ int width, height;
+} avis_hnd_t;
+
+static int open_file( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
+{
+ avis_hnd_t *h = malloc( sizeof(avis_hnd_t) );
+ if( !h )
+ return -1;
+ AVISTREAMINFO info;
+ int i;
+
+ *p_handle = h;
+
+ AVIFileInit();
+ if( AVIStreamOpenFromFile( &h->p_avi, psz_filename, streamtypeVIDEO, 0, OF_READ, NULL ) )
+ {
+ AVIFileExit();
+ return -1;
+ }
+
+ if( AVIStreamInfo( h->p_avi, &info, sizeof(AVISTREAMINFO) ) )
+ {
+ AVIStreamRelease( h->p_avi );
+ AVIFileExit();
+ return -1;
+ }
+
+ // check input format
+ if( info.fccHandler != MAKEFOURCC('Y', 'V', '1', '2') )
+ {
+ fprintf( stderr, "avis [error]: unsupported input format (%c%c%c%c)\n",
+ (char)(info.fccHandler & 0xff), (char)((info.fccHandler >> 8) & 0xff),
+ (char)((info.fccHandler >> 16) & 0xff), (char)((info.fccHandler >> 24)) );
+
+ AVIStreamRelease( h->p_avi );
+ AVIFileExit();
+
+ return -1;
+ }
+
+ h->width =
+ p_param->i_width = info.rcFrame.right - info.rcFrame.left;
+ h->height =
+ p_param->i_height = info.rcFrame.bottom - info.rcFrame.top;
+ i = gcd( info.dwRate, info.dwScale );
+ p_param->i_fps_den = info.dwScale / i;
+ p_param->i_fps_num = info.dwRate / i;
+
+ fprintf( stderr, "avis [info]: %dx%d @ %.2f fps (%d frames)\n",
+ p_param->i_width, p_param->i_height,
+ (double)p_param->i_fps_num / (double)p_param->i_fps_den,
+ (int)info.dwLength );
+
+ return 0;
+}
+
+static int get_frame_total( hnd_t handle )
+{
+ avis_hnd_t *h = handle;
+ AVISTREAMINFO info;
+
+ if( AVIStreamInfo( h->p_avi, &info, sizeof(AVISTREAMINFO) ) )
+ return -1;
+
+ return info.dwLength;
+}
+
+static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
+{
+ avis_hnd_t *h = handle;
+
+ p_pic->img.i_csp = X264_CSP_YV12;
+
+ if( AVIStreamRead( h->p_avi, i_frame, 1, p_pic->img.plane[0], h->width * h->height * 3 / 2, NULL, NULL ) )
+ return -1;
+
+ return 0;
+}
+
+static int close_file( hnd_t handle )
+{
+ avis_hnd_t *h = handle;
+ AVIStreamRelease( h->p_avi );
+ AVIFileExit();
+ free( h );
+ return 0;
+}
+
+cli_input_t avis_input = { open_file, get_frame_total, read_frame, close_file };
--- /dev/null
+/*****************************************************************************
+ * input.h: x264 file input modules
+ *****************************************************************************
+ * Copyright (C) 2003-2009 x264 project
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * Loren Merritt <lorenm@u.washington.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#ifndef X264_INPUT_H
+#define X264_INPUT_H
+
+typedef struct
+{
+ int (*open_file)( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
+ int (*get_frame_total)( hnd_t handle );
+ int (*read_frame)( x264_picture_t *p_pic, hnd_t handle, int i_frame );
+ int (*close_file)( hnd_t handle );
+} cli_input_t;
+
+extern cli_input_t yuv_input;
+extern cli_input_t y4m_input;
+extern cli_input_t avis_input;
+extern cli_input_t thread_input;
+
+#endif
--- /dev/null
+/*****************************************************************************
+ * thread.c: x264 threaded input module
+ *****************************************************************************
+ * Copyright (C) 2003-2009 x264 project
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * Loren Merritt <lorenm@u.washington.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#include "muxers.h"
+
+extern cli_input_t input;
+
+typedef struct
+{
+ cli_input_t input;
+ hnd_t p_handle;
+ x264_picture_t pic;
+ x264_pthread_t tid;
+ int next_frame;
+ int frame_total;
+ int in_progress;
+ struct thread_input_arg_t *next_args;
+} thread_hnd_t;
+
+typedef struct thread_input_arg_t
+{
+ thread_hnd_t *h;
+ x264_picture_t *pic;
+ int i_frame;
+ int status;
+} thread_input_arg_t;
+
+static int open_file( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
+{
+ thread_hnd_t *h = malloc( sizeof(thread_hnd_t) );
+ if( !h || x264_picture_alloc( &h->pic, X264_CSP_I420, p_param->i_width, p_param->i_height ) < 0 )
+ {
+ fprintf( stderr, "x264 [error]: malloc failed\n" );
+ return -1;
+ }
+ h->input = input;
+ h->p_handle = *p_handle;
+ h->in_progress = 0;
+ h->next_frame = -1;
+ h->next_args = malloc( sizeof(thread_input_arg_t) );
+ if( !h->next_args )
+ return -1;
+ h->next_args->h = h;
+ h->next_args->status = 0;
+ h->frame_total = input.get_frame_total( h->p_handle );
+
+ *p_handle = h;
+ return 0;
+}
+
+static int get_frame_total( hnd_t handle )
+{
+ thread_hnd_t *h = handle;
+ return h->frame_total;
+}
+
+static void read_frame_thread_int( thread_input_arg_t *i )
+{
+ i->status = i->h->input.read_frame( i->pic, i->h->p_handle, i->i_frame );
+}
+
+static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
+{
+ thread_hnd_t *h = handle;
+ int ret = 0;
+
+ if( h->next_frame >= 0 )
+ {
+ x264_pthread_join( h->tid, NULL );
+ ret |= h->next_args->status;
+ h->in_progress = 0;
+ }
+
+ if( h->next_frame == i_frame )
+ XCHG( x264_picture_t, *p_pic, h->pic );
+ else
+ ret |= h->input.read_frame( p_pic, h->p_handle, i_frame );
+
+ if( !h->frame_total || i_frame+1 < h->frame_total )
+ {
+ h->next_frame =
+ h->next_args->i_frame = i_frame+1;
+ h->next_args->pic = &h->pic;
+ if( x264_pthread_create( &h->tid, NULL, (void*)read_frame_thread_int, h->next_args ) )
+ return -1;
+ h->in_progress = 1;
+ }
+ else
+ h->next_frame = -1;
+
+ return ret;
+}
+
+static int close_file( hnd_t handle )
+{
+ thread_hnd_t *h = handle;
+ if( h->in_progress )
+ x264_pthread_join( h->tid, NULL );
+ h->input.close_file( h->p_handle );
+ x264_picture_clean( &h->pic );
+ free( h->next_args );
+ free( h );
+ return 0;
+}
+
+cli_input_t thread_input = { open_file, get_frame_total, read_frame, close_file };
--- /dev/null
+/*****************************************************************************
+ * y4m.c: x264 y4m input module
+ *****************************************************************************
+ * Copyright (C) 2003-2009 x264 project
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * Loren Merritt <lorenm@u.washington.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#include "muxers.h"
+
+typedef struct
+{
+ FILE *fh;
+ int width, height;
+ int next_frame;
+ int seq_header_len, frame_header_len;
+ int frame_size;
+} y4m_hnd_t;
+
+#define Y4M_MAGIC "YUV4MPEG2"
+#define MAX_YUV4_HEADER 80
+#define Y4M_FRAME_MAGIC "FRAME"
+#define MAX_FRAME_HEADER 80
+
+static int open_file( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
+{
+ y4m_hnd_t *h = malloc( sizeof(y4m_hnd_t) );
+ int i, n, d;
+ char header[MAX_YUV4_HEADER+10];
+ char *tokstart, *tokend, *header_end;
+ if( !h )
+ return -1;
+
+ h->next_frame = 0;
+
+ if( !strcmp( psz_filename, "-" ) )
+ h->fh = stdin;
+ else
+ h->fh = fopen(psz_filename, "rb");
+ if( h->fh == NULL )
+ return -1;
+
+ h->frame_header_len = strlen( Y4M_FRAME_MAGIC )+1;
+
+ /* Read header */
+ for( i = 0; i < MAX_YUV4_HEADER; i++ )
+ {
+ header[i] = fgetc( h->fh );
+ if( header[i] == '\n' )
+ {
+ /* Add a space after last option. Makes parsing "444" vs
+ "444alpha" easier. */
+ header[i+1] = 0x20;
+ header[i+2] = 0;
+ break;
+ }
+ }
+ if( i == MAX_YUV4_HEADER || strncmp( header, Y4M_MAGIC, strlen( Y4M_MAGIC ) ) )
+ return -1;
+
+ /* Scan properties */
+ header_end = &header[i+1]; /* Include space */
+ h->seq_header_len = i+1;
+ for( tokstart = &header[strlen( Y4M_MAGIC )+1]; tokstart < header_end; tokstart++ )
+ {
+ if( *tokstart == 0x20 )
+ continue;
+ switch( *tokstart++ )
+ {
+ case 'W': /* Width. Required. */
+ h->width = p_param->i_width = strtol( tokstart, &tokend, 10 );
+ tokstart=tokend;
+ break;
+ case 'H': /* Height. Required. */
+ h->height = p_param->i_height = strtol( tokstart, &tokend, 10 );
+ tokstart=tokend;
+ break;
+ case 'C': /* Color space */
+ if( strncmp( "420", tokstart, 3 ) )
+ {
+ fprintf( stderr, "Colorspace unhandled\n" );
+ return -1;
+ }
+ tokstart = strchr( tokstart, 0x20 );
+ break;
+ case 'I': /* Interlace type */
+ switch( *tokstart++ )
+ {
+ case 'p': break;
+ case '?':
+ case 't':
+ case 'b':
+ case 'm':
+ default:
+ fprintf( stderr, "Warning, this sequence might be interlaced\n" );
+ }
+ break;
+ case 'F': /* Frame rate - 0:0 if unknown */
+ if( sscanf( tokstart, "%d:%d", &n, &d ) == 2 && n && d )
+ {
+ x264_reduce_fraction( &n, &d );
+ p_param->i_fps_num = n;
+ p_param->i_fps_den = d;
+ }
+ tokstart = strchr( tokstart, 0x20 );
+ break;
+ case 'A': /* Pixel aspect - 0:0 if unknown */
+ /* Don't override the aspect ratio if sar has been explicitly set on the commandline. */
+ if( sscanf( tokstart, "%d:%d", &n, &d ) == 2 && n && d && !p_param->vui.i_sar_width && !p_param->vui.i_sar_height )
+ {
+ x264_reduce_fraction( &n, &d );
+ p_param->vui.i_sar_width = n;
+ p_param->vui.i_sar_height = d;
+ }
+ tokstart = strchr( tokstart, 0x20 );
+ break;
+ case 'X': /* Vendor extensions */
+ if( !strncmp( "YSCSS=", tokstart, 6 ) )
+ {
+ /* Older nonstandard pixel format representation */
+ tokstart += 6;
+ if( strncmp( "420JPEG",tokstart, 7 ) &&
+ strncmp( "420MPEG2",tokstart, 8 ) &&
+ strncmp( "420PALDV",tokstart, 8 ) )
+ {
+ fprintf( stderr, "Unsupported extended colorspace\n" );
+ return -1;
+ }
+ }
+ tokstart = strchr( tokstart, 0x20 );
+ break;
+ }
+ }
+
+ fprintf( stderr, "yuv4mpeg: %ix%i@%i/%ifps, %i:%i\n",
+ h->width, h->height, p_param->i_fps_num, p_param->i_fps_den,
+ p_param->vui.i_sar_width, p_param->vui.i_sar_height );
+
+ *p_handle = h;
+ return 0;
+}
+
+/* Most common case: frame_header = "FRAME" */
+static int get_frame_total( hnd_t handle )
+{
+ y4m_hnd_t *h = handle;
+ int i_frame_total = 0;
+ uint64_t init_pos = ftell( h->fh );
+
+ if( !fseek( h->fh, 0, SEEK_END ) )
+ {
+ uint64_t i_size = ftell( h->fh );
+ fseek( h->fh, init_pos, SEEK_SET );
+ i_frame_total = (int)((i_size - h->seq_header_len) /
+ (3*(h->width*h->height)/2+h->frame_header_len));
+ }
+
+ return i_frame_total;
+}
+
+static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
+{
+ y4m_hnd_t *h = handle;
+ int slen = strlen( Y4M_FRAME_MAGIC );
+ int i = 0;
+ char header[16];
+
+ if( i_frame != h->next_frame )
+ {
+ if( fseek( h->fh, (uint64_t)i_frame*(3*(h->width*h->height)/2+h->frame_header_len)
+ + h->seq_header_len, SEEK_SET ) )
+ return -1;
+ }
+
+ /* Read frame header - without terminating '\n' */
+ if( fread( header, 1, slen, h->fh ) != slen )
+ return -1;
+
+ header[slen] = 0;
+ if( strncmp( header, Y4M_FRAME_MAGIC, slen ) )
+ {
+ fprintf( stderr, "Bad header magic (%"PRIx32" <=> %s)\n",
+ *((uint32_t*)header), header );
+ return -1;
+ }
+
+ /* Skip most of it */
+ while( i < MAX_FRAME_HEADER && fgetc( h->fh ) != '\n' )
+ i++;
+ if( i == MAX_FRAME_HEADER )
+ {
+ fprintf( stderr, "Bad frame header!\n" );
+ return -1;
+ }
+ h->frame_header_len = i+slen+1;
+
+ if( fread( p_pic->img.plane[0], 1, h->width*h->height, h->fh ) <= 0
+ || fread( p_pic->img.plane[1], 1, h->width * h->height / 4, h->fh ) <= 0
+ || fread( p_pic->img.plane[2], 1, h->width * h->height / 4, h->fh ) <= 0 )
+ return -1;
+
+ h->next_frame = i_frame+1;
+
+ return 0;
+}
+
+static int close_file( hnd_t handle )
+{
+ y4m_hnd_t *h = handle;
+ if( !h || !h->fh )
+ return 0;
+ fclose( h->fh );
+ free( h );
+ return 0;
+}
+
+cli_input_t y4m_input = { open_file, get_frame_total, read_frame, close_file };
--- /dev/null
+/*****************************************************************************
+ * yuv.c: x264 yuv input module
+ *****************************************************************************
+ * Copyright (C) 2003-2009 x264 project
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * Loren Merritt <lorenm@u.washington.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#include "muxers.h"
+
+typedef struct
+{
+ FILE *fh;
+ int width, height;
+ int next_frame;
+} yuv_hnd_t;
+
+static int open_file( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
+{
+ yuv_hnd_t *h = malloc( sizeof(yuv_hnd_t) );
+ if( !h )
+ return -1;
+ h->width = p_param->i_width;
+ h->height = p_param->i_height;
+ h->next_frame = 0;
+
+ if( !strcmp( psz_filename, "-" ) )
+ h->fh = stdin;
+ else
+ h->fh = fopen( psz_filename, "rb" );
+ if( h->fh == NULL )
+ return -1;
+
+ *p_handle = h;
+ return 0;
+}
+
+static int get_frame_total( hnd_t handle )
+{
+ yuv_hnd_t *h = handle;
+ int i_frame_total = 0;
+
+ if( !fseek( h->fh, 0, SEEK_END ) )
+ {
+ uint64_t i_size = ftell( h->fh );
+ fseek( h->fh, 0, SEEK_SET );
+ i_frame_total = (int)(i_size / ( h->width * h->height * 3 / 2 ));
+ }
+
+ return i_frame_total;
+}
+
+static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
+{
+ yuv_hnd_t *h = handle;
+
+ if( i_frame != h->next_frame )
+ if( fseek( h->fh, (uint64_t)i_frame * h->width * h->height * 3 / 2, SEEK_SET ) )
+ return -1;
+
+ if( fread( p_pic->img.plane[0], 1, h->width * h->height, h->fh ) <= 0
+ || fread( p_pic->img.plane[1], 1, h->width * h->height / 4, h->fh ) <= 0
+ || fread( p_pic->img.plane[2], 1, h->width * h->height / 4, h->fh ) <= 0 )
+ return -1;
+
+ h->next_frame = i_frame+1;
+
+ return 0;
+}
+
+static int close_file( hnd_t handle )
+{
+ yuv_hnd_t *h = handle;
+ if( !h || !h->fh )
+ return 0;
+ fclose( h->fh );
+ free( h );
+ return 0;
+}
+
+cli_input_t yuv_input = { open_file, get_frame_total, read_frame, close_file };
+++ /dev/null
-/*****************************************************************************
- * muxers.c: h264 file i/o plugins
- *****************************************************************************
- * Copyright (C) 2003-2008 x264 project
- *
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- * Loren Merritt <lorenm@u.washington.edu>
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
- *****************************************************************************/
-
-#include "common/common.h"
-#include "x264.h"
-#include "matroska.h"
-#include "muxers.h"
-#include "config.h"
-
-#include <sys/types.h>
-
-#ifdef AVIS_INPUT
-#include <windows.h>
-#include <vfw.h>
-#endif
-
-#ifdef MP4_OUTPUT
-#include <gpac/isomedia.h>
-#endif
-
-static int64_t gcd( int64_t a, int64_t b )
-{
- while( 1 )
- {
- int64_t c = a % b;
- if( !c )
- return b;
- a = b;
- b = c;
- }
-}
-
-typedef struct
-{
- FILE *fh;
- int width, height;
- int next_frame;
-} yuv_input_t;
-
-/* raw 420 yuv file operation */
-int open_file_yuv( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
-{
- yuv_input_t *h = malloc( sizeof(yuv_input_t) );
- if( !h )
- return -1;
- h->width = p_param->i_width;
- h->height = p_param->i_height;
- h->next_frame = 0;
-
- if( !strcmp( psz_filename, "-" ) )
- h->fh = stdin;
- else
- h->fh = fopen( psz_filename, "rb" );
- if( h->fh == NULL )
- return -1;
-
- *p_handle = (hnd_t)h;
- return 0;
-}
-
-int get_frame_total_yuv( hnd_t handle )
-{
- yuv_input_t *h = handle;
- int i_frame_total = 0;
-
- if( !fseek( h->fh, 0, SEEK_END ) )
- {
- uint64_t i_size = ftell( h->fh );
- fseek( h->fh, 0, SEEK_SET );
- i_frame_total = (int)(i_size / ( h->width * h->height * 3 / 2 ));
- }
-
- return i_frame_total;
-}
-
-int read_frame_yuv( x264_picture_t *p_pic, hnd_t handle, int i_frame )
-{
- yuv_input_t *h = handle;
-
- if( i_frame != h->next_frame )
- if( fseek( h->fh, (uint64_t)i_frame * h->width * h->height * 3 / 2, SEEK_SET ) )
- return -1;
-
- if( fread( p_pic->img.plane[0], 1, h->width * h->height, h->fh ) <= 0
- || fread( p_pic->img.plane[1], 1, h->width * h->height / 4, h->fh ) <= 0
- || fread( p_pic->img.plane[2], 1, h->width * h->height / 4, h->fh ) <= 0 )
- return -1;
-
- h->next_frame = i_frame+1;
-
- return 0;
-}
-
-int close_file_yuv(hnd_t handle)
-{
- yuv_input_t *h = handle;
- if( !h || !h->fh )
- return 0;
- fclose( h->fh );
- free( h );
- return 0;
-}
-
-/* YUV4MPEG2 raw 420 yuv file operation */
-typedef struct
-{
- FILE *fh;
- int width, height;
- int next_frame;
- int seq_header_len, frame_header_len;
- int frame_size;
-} y4m_input_t;
-
-#define Y4M_MAGIC "YUV4MPEG2"
-#define MAX_YUV4_HEADER 80
-#define Y4M_FRAME_MAGIC "FRAME"
-#define MAX_FRAME_HEADER 80
-
-int open_file_y4m( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
-{
- int i, n, d;
- char header[MAX_YUV4_HEADER+10];
- char *tokstart, *tokend, *header_end;
- y4m_input_t *h = malloc( sizeof(y4m_input_t) );
- if( !h )
- return -1;
-
- h->next_frame = 0;
-
- if( !strcmp( psz_filename, "-" ) )
- h->fh = stdin;
- else
- h->fh = fopen(psz_filename, "rb");
- if( h->fh == NULL )
- return -1;
-
- h->frame_header_len = strlen(Y4M_FRAME_MAGIC)+1;
-
- /* Read header */
- for( i = 0; i < MAX_YUV4_HEADER; i++ )
- {
- header[i] = fgetc(h->fh);
- if( header[i] == '\n' )
- {
- /* Add a space after last option. Makes parsing "444" vs
- "444alpha" easier. */
- header[i+1] = 0x20;
- header[i+2] = 0;
- break;
- }
- }
- if( i == MAX_YUV4_HEADER || strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC)) )
- return -1;
-
- /* Scan properties */
- header_end = &header[i+1]; /* Include space */
- h->seq_header_len = i+1;
- for( tokstart = &header[strlen(Y4M_MAGIC)+1]; tokstart < header_end; tokstart++ )
- {
- if( *tokstart == 0x20 )
- continue;
- switch(*tokstart++)
- {
- case 'W': /* Width. Required. */
- h->width = p_param->i_width = strtol( tokstart, &tokend, 10 );
- tokstart=tokend;
- break;
- case 'H': /* Height. Required. */
- h->height = p_param->i_height = strtol( tokstart, &tokend, 10 );
- tokstart=tokend;
- break;
- case 'C': /* Color space */
- if( strncmp( "420", tokstart, 3 ) )
- {
- fprintf( stderr, "Colorspace unhandled\n" );
- return -1;
- }
- tokstart = strchr( tokstart, 0x20 );
- break;
- case 'I': /* Interlace type */
- switch( *tokstart++ )
- {
- case 'p': break;
- case '?':
- case 't':
- case 'b':
- case 'm':
- default:
- fprintf( stderr, "Warning, this sequence might be interlaced\n" );
- }
- break;
- case 'F': /* Frame rate - 0:0 if unknown */
- if( sscanf( tokstart, "%d:%d", &n, &d ) == 2 && n && d )
- {
- x264_reduce_fraction( &n, &d );
- p_param->i_fps_num = n;
- p_param->i_fps_den = d;
- }
- tokstart = strchr( tokstart, 0x20 );
- break;
- case 'A': /* Pixel aspect - 0:0 if unknown */
- /* Don't override the aspect ratio if sar has been explicitly set on the commandline. */
- if( sscanf( tokstart, "%d:%d", &n, &d ) == 2 && n && d && !p_param->vui.i_sar_width && !p_param->vui.i_sar_height )
- {
- x264_reduce_fraction( &n, &d );
- p_param->vui.i_sar_width = n;
- p_param->vui.i_sar_height = d;
- }
- tokstart = strchr( tokstart, 0x20 );
- break;
- case 'X': /* Vendor extensions */
- if( !strncmp( "YSCSS=", tokstart, 6 ) )
- {
- /* Older nonstandard pixel format representation */
- tokstart += 6;
- if( strncmp( "420JPEG",tokstart, 7 ) &&
- strncmp( "420MPEG2",tokstart, 8 ) &&
- strncmp( "420PALDV",tokstart, 8 ) )
- {
- fprintf( stderr, "Unsupported extended colorspace\n" );
- return -1;
- }
- }
- tokstart = strchr(tokstart, 0x20);
- break;
- }
- }
-
- fprintf( stderr, "yuv4mpeg: %ix%i@%i/%ifps, %i:%i\n",
- h->width, h->height, p_param->i_fps_num, p_param->i_fps_den,
- p_param->vui.i_sar_width, p_param->vui.i_sar_height );
-
- *p_handle = (hnd_t)h;
- return 0;
-}
-
-/* Most common case: frame_header = "FRAME" */
-int get_frame_total_y4m( hnd_t handle )
-{
- y4m_input_t *h = handle;
- int i_frame_total = 0;
- uint64_t init_pos = ftell(h->fh);
-
- if( !fseek( h->fh, 0, SEEK_END ) )
- {
- uint64_t i_size = ftell( h->fh );
- fseek( h->fh, init_pos, SEEK_SET );
- i_frame_total = (int)((i_size - h->seq_header_len) /
- (3*(h->width*h->height)/2+h->frame_header_len));
- }
-
- return i_frame_total;
-}
-
-int read_frame_y4m( x264_picture_t *p_pic, hnd_t handle, int i_frame )
-{
- int slen = strlen(Y4M_FRAME_MAGIC);
- int i = 0;
- char header[16];
- y4m_input_t *h = handle;
-
- if( i_frame != h->next_frame )
- {
- if( fseek( h->fh, (uint64_t)i_frame*(3*(h->width*h->height)/2+h->frame_header_len)
- + h->seq_header_len, SEEK_SET ) )
- return -1;
- }
-
- /* Read frame header - without terminating '\n' */
- if( fread( header, 1, slen, h->fh ) != slen )
- return -1;
-
- header[slen] = 0;
- if( strncmp( header, Y4M_FRAME_MAGIC, slen ) )
- {
- fprintf( stderr, "Bad header magic (%"PRIx32" <=> %s)\n",
- *((uint32_t*)header), header );
- return -1;
- }
-
- /* Skip most of it */
- while( i<MAX_FRAME_HEADER && fgetc(h->fh) != '\n' )
- i++;
- if( i == MAX_FRAME_HEADER )
- {
- fprintf( stderr, "Bad frame header!\n" );
- return -1;
- }
- h->frame_header_len = i+slen+1;
-
- if( fread( p_pic->img.plane[0], 1, h->width*h->height, h->fh ) <= 0
- || fread( p_pic->img.plane[1], 1, h->width * h->height / 4, h->fh ) <= 0
- || fread( p_pic->img.plane[2], 1, h->width * h->height / 4, h->fh ) <= 0)
- return -1;
-
- h->next_frame = i_frame+1;
-
- return 0;
-}
-
-int close_file_y4m(hnd_t handle)
-{
- y4m_input_t *h = handle;
- if( !h || !h->fh )
- return 0;
- fclose( h->fh );
- free( h );
- return 0;
-}
-
-/* avs/avi input file support under cygwin */
-
-#ifdef AVIS_INPUT
-typedef struct
-{
- PAVISTREAM p_avi;
- int width, height;
-} avis_input_t;
-
-int open_file_avis( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
-{
- avis_input_t *h = malloc( sizeof(avis_input_t) );
- if( !h )
- return -1;
- AVISTREAMINFO info;
- int i;
-
- *p_handle = (hnd_t)h;
-
- AVIFileInit();
- if( AVIStreamOpenFromFile( &h->p_avi, psz_filename, streamtypeVIDEO, 0, OF_READ, NULL ) )
- {
- AVIFileExit();
- return -1;
- }
-
- if( AVIStreamInfo( h->p_avi, &info, sizeof(AVISTREAMINFO) ) )
- {
- AVIStreamRelease(h->p_avi);
- AVIFileExit();
- return -1;
- }
-
- // check input format
- if( info.fccHandler != MAKEFOURCC('Y', 'V', '1', '2') )
- {
- fprintf( stderr, "avis [error]: unsupported input format (%c%c%c%c)\n",
- (char)(info.fccHandler & 0xff), (char)((info.fccHandler >> 8) & 0xff),
- (char)((info.fccHandler >> 16) & 0xff), (char)((info.fccHandler >> 24)) );
-
- AVIStreamRelease( h->p_avi );
- AVIFileExit();
-
- return -1;
- }
-
- h->width =
- p_param->i_width = info.rcFrame.right - info.rcFrame.left;
- h->height =
- p_param->i_height = info.rcFrame.bottom - info.rcFrame.top;
- i = gcd(info.dwRate, info.dwScale);
- p_param->i_fps_den = info.dwScale / i;
- p_param->i_fps_num = info.dwRate / i;
-
- fprintf( stderr, "avis [info]: %dx%d @ %.2f fps (%d frames)\n",
- p_param->i_width, p_param->i_height,
- (double)p_param->i_fps_num / (double)p_param->i_fps_den,
- (int)info.dwLength );
-
- return 0;
-}
-
-int get_frame_total_avis( hnd_t handle )
-{
- avis_input_t *h = handle;
- AVISTREAMINFO info;
-
- if( AVIStreamInfo( h->p_avi, &info, sizeof(AVISTREAMINFO) ) )
- return -1;
-
- return info.dwLength;
-}
-
-int read_frame_avis( x264_picture_t *p_pic, hnd_t handle, int i_frame )
-{
- avis_input_t *h = handle;
-
- p_pic->img.i_csp = X264_CSP_YV12;
-
- if( AVIStreamRead( h->p_avi, i_frame, 1, p_pic->img.plane[0], h->width * h->height * 3 / 2, NULL, NULL ) )
- return -1;
-
- return 0;
-}
-
-int close_file_avis( hnd_t handle )
-{
- avis_input_t *h = handle;
- AVIStreamRelease( h->p_avi );
- AVIFileExit();
- free( h );
- return 0;
-}
-#endif
-
-
-#ifdef HAVE_PTHREAD
-typedef struct
-{
- int (*p_read_frame)( x264_picture_t *p_pic, hnd_t handle, int i_frame );
- int (*p_close_infile)( hnd_t handle );
- hnd_t p_handle;
- x264_picture_t pic;
- x264_pthread_t tid;
- int next_frame;
- int frame_total;
- int in_progress;
- struct thread_input_arg_t *next_args;
-} thread_input_t;
-
-typedef struct thread_input_arg_t
-{
- thread_input_t *h;
- x264_picture_t *pic;
- int i_frame;
- int status;
-} thread_input_arg_t;
-
-int open_file_thread( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
-{
- thread_input_t *h = malloc( sizeof(thread_input_t) );
- if( !h || x264_picture_alloc( &h->pic, X264_CSP_I420, p_param->i_width, p_param->i_height ) < 0 )
- {
- fprintf( stderr, "x264 [error]: malloc failed\n" );
- return -1;
- }
- h->p_read_frame = p_read_frame;
- h->p_close_infile = p_close_infile;
- h->p_handle = *p_handle;
- h->in_progress = 0;
- h->next_frame = -1;
- h->next_args = malloc(sizeof(thread_input_arg_t));
- if( !h->next_args )
- return -1;
- h->next_args->h = h;
- h->next_args->status = 0;
- h->frame_total = p_get_frame_total( h->p_handle );
-
- *p_handle = (hnd_t)h;
- return 0;
-}
-
-int get_frame_total_thread( hnd_t handle )
-{
- thread_input_t *h = handle;
- return h->frame_total;
-}
-
-static void read_frame_thread_int( thread_input_arg_t *i )
-{
- i->status = i->h->p_read_frame( i->pic, i->h->p_handle, i->i_frame );
-}
-
-int read_frame_thread( x264_picture_t *p_pic, hnd_t handle, int i_frame )
-{
- thread_input_t *h = handle;
- int ret = 0;
-
- if( h->next_frame >= 0 )
- {
- x264_pthread_join( h->tid, NULL );
- ret |= h->next_args->status;
- h->in_progress = 0;
- }
-
- if( h->next_frame == i_frame )
- {
- XCHG( x264_picture_t, *p_pic, h->pic );
- }
- else
- {
- ret |= h->p_read_frame( p_pic, h->p_handle, i_frame );
- }
-
- if( !h->frame_total || i_frame+1 < h->frame_total )
- {
- h->next_frame =
- h->next_args->i_frame = i_frame+1;
- h->next_args->pic = &h->pic;
- if( x264_pthread_create( &h->tid, NULL, (void*)read_frame_thread_int, h->next_args ) )
- return -1;
- h->in_progress = 1;
- }
- else
- h->next_frame = -1;
-
- return ret;
-}
-
-int close_file_thread( hnd_t handle )
-{
- thread_input_t *h = handle;
- if( h->in_progress )
- x264_pthread_join( h->tid, NULL );
- h->p_close_infile( h->p_handle );
- x264_picture_clean( &h->pic );
- free( h->next_args );
- free( h );
- return 0;
-}
-#endif
-
-
-int open_file_bsf( char *psz_filename, hnd_t *p_handle )
-{
- if( !(*p_handle = fopen(psz_filename, "w+b")) )
- return -1;
-
- return 0;
-}
-
-int set_param_bsf( hnd_t handle, x264_param_t *p_param )
-{
- return 0;
-}
-
-int write_nalu_bsf( hnd_t handle, uint8_t *p_nalu, int i_size )
-{
- if( fwrite( p_nalu, i_size, 1, (FILE*)handle ) > 0 )
- return i_size;
- return -1;
-}
-
-int set_eop_bsf( hnd_t handle, x264_picture_t *p_picture )
-{
- return 0;
-}
-
-int close_file_bsf( hnd_t handle )
-{
- if( !handle || handle == stdout )
- return 0;
-
- return fclose( (FILE*)handle );
-}
-
-/* -- mp4 muxing support ------------------------------------------------- */
-#ifdef MP4_OUTPUT
-
-typedef struct
-{
- GF_ISOFile *p_file;
- GF_AVCConfig *p_config;
- GF_ISOSample *p_sample;
- int i_track;
- uint32_t i_descidx;
- int i_time_inc;
- int i_time_res;
- int i_numframe;
- int i_init_delay;
- uint8_t b_sps;
- uint8_t b_pps;
-} mp4_t;
-
-
-static void recompute_bitrate_mp4(GF_ISOFile *p_file, int i_track)
-{
- u32 i, count, di, timescale, time_wnd, rate;
- u64 offset;
- Double br;
- GF_ESD *esd;
-
- esd = gf_isom_get_esd( p_file, i_track, 1 );
- if( !esd )
- return;
-
- esd->decoderConfig->avgBitrate = 0;
- esd->decoderConfig->maxBitrate = 0;
- rate = time_wnd = 0;
-
- timescale = gf_isom_get_media_timescale( p_file, i_track );
- count = gf_isom_get_sample_count( p_file, i_track );
- for( i = 0; i < count; i++ )
- {
- GF_ISOSample *samp = gf_isom_get_sample_info( p_file, i_track, i+1, &di, &offset );
-
- if( samp->dataLength>esd->decoderConfig->bufferSizeDB )
- esd->decoderConfig->bufferSizeDB = samp->dataLength;
-
- if( esd->decoderConfig->bufferSizeDB < samp->dataLength )
- esd->decoderConfig->bufferSizeDB = samp->dataLength;
-
- esd->decoderConfig->avgBitrate += samp->dataLength;
- rate += samp->dataLength;
- if( samp->DTS > time_wnd + timescale )
- {
- if( rate > esd->decoderConfig->maxBitrate )
- esd->decoderConfig->maxBitrate = rate;
- time_wnd = samp->DTS;
- rate = 0;
- }
-
- gf_isom_sample_del( &samp );
- }
-
- br = (Double)(s64)gf_isom_get_media_duration( p_file, i_track );
- br /= timescale;
- esd->decoderConfig->avgBitrate = (u32)(esd->decoderConfig->avgBitrate / br);
- /*move to bps*/
- esd->decoderConfig->avgBitrate *= 8;
- esd->decoderConfig->maxBitrate *= 8;
-
- gf_isom_change_mpeg4_description( p_file, i_track, 1, esd );
- gf_odf_desc_del( (GF_Descriptor*)esd );
-}
-
-
-int close_file_mp4( hnd_t handle )
-{
- mp4_t *p_mp4 = (mp4_t*)handle;
-
- if( !p_mp4 )
- return 0;
-
- if( p_mp4->p_config )
- gf_odf_avc_cfg_del( p_mp4->p_config );
-
- if( p_mp4->p_sample )
- {
- if( p_mp4->p_sample->data )
- free( p_mp4->p_sample->data );
-
- gf_isom_sample_del( &p_mp4->p_sample );
- }
-
- if( p_mp4->p_file )
- {
- recompute_bitrate_mp4( p_mp4->p_file, p_mp4->i_track );
- gf_isom_set_pl_indication( p_mp4->p_file, GF_ISOM_PL_VISUAL, 0x15 );
- gf_isom_set_storage_mode( p_mp4->p_file, GF_ISOM_STORE_FLAT );
- gf_isom_close( p_mp4->p_file );
- }
-
- free( p_mp4 );
-
- return 0;
-}
-
-int open_file_mp4( char *psz_filename, hnd_t *p_handle )
-{
- mp4_t *p_mp4;
-
- *p_handle = NULL;
-
- if( !(p_mp4 = malloc(sizeof(mp4_t))) )
- return -1;
-
- memset( p_mp4, 0, sizeof(mp4_t) );
- p_mp4->p_file = gf_isom_open( psz_filename, GF_ISOM_OPEN_WRITE, NULL );
-
- if( !(p_mp4->p_sample = gf_isom_sample_new()) )
- {
- close_file_mp4( p_mp4 );
- return -1;
- }
-
- gf_isom_set_brand_info( p_mp4->p_file, GF_ISOM_BRAND_AVC1, 0 );
-
- *p_handle = p_mp4;
-
- return 0;
-}
-
-
-int set_param_mp4( hnd_t handle, x264_param_t *p_param )
-{
- mp4_t *p_mp4 = (mp4_t*)handle;
-
- p_mp4->i_track = gf_isom_new_track( p_mp4->p_file, 0, GF_ISOM_MEDIA_VISUAL,
- p_param->i_fps_num );
-
- p_mp4->p_config = gf_odf_avc_cfg_new();
- gf_isom_avc_config_new( p_mp4->p_file, p_mp4->i_track, p_mp4->p_config,
- NULL, NULL, &p_mp4->i_descidx );
-
- gf_isom_set_track_enabled( p_mp4->p_file, p_mp4->i_track, 1 );
-
- gf_isom_set_visual_info( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx,
- p_param->i_width, p_param->i_height );
-
- if( p_param->vui.i_sar_width && p_param->vui.i_sar_height )
- {
- uint64_t dw = p_param->i_width << 16;
- uint64_t dh = p_param->i_height << 16;
- double sar = (double)p_param->vui.i_sar_width / p_param->vui.i_sar_height;
- if( sar > 1.0 )
- dw *= sar ;
- else
- dh /= sar;
- gf_isom_set_track_layout_info( p_mp4->p_file, p_mp4->i_track, dw, dh, 0, 0, 0 );
- }
-
- p_mp4->p_sample->data = malloc( p_param->i_width * p_param->i_height * 3 / 2 );
- if( !p_mp4->p_sample->data )
- return -1;
-
- p_mp4->i_time_res = p_param->i_fps_num;
- p_mp4->i_time_inc = p_param->i_fps_den;
- p_mp4->i_init_delay = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0;
- p_mp4->i_init_delay *= p_mp4->i_time_inc;
- fprintf( stderr, "mp4 [info]: initial delay %d (scale %d)\n",
- p_mp4->i_init_delay, p_mp4->i_time_res );
-
- return 0;
-}
-
-
-int write_nalu_mp4( hnd_t handle, uint8_t *p_nalu, int i_size )
-{
- mp4_t *p_mp4 = (mp4_t*)handle;
- GF_AVCConfigSlot *p_slot;
- uint8_t type = p_nalu[4] & 0x1f;
- int psize;
-
- switch( type )
- {
- // sps
- case 0x07:
- if( !p_mp4->b_sps )
- {
- p_mp4->p_config->configurationVersion = 1;
- p_mp4->p_config->AVCProfileIndication = p_nalu[5];
- p_mp4->p_config->profile_compatibility = p_nalu[6];
- p_mp4->p_config->AVCLevelIndication = p_nalu[7];
- p_slot = malloc( sizeof(GF_AVCConfigSlot) );
- if( !p_slot )
- return -1;
- p_slot->size = i_size - 4;
- p_slot->data = malloc( p_slot->size );
- if( !p_slot->data )
- return -1;
- memcpy( p_slot->data, p_nalu + 4, i_size - 4 );
- gf_list_add( p_mp4->p_config->sequenceParameterSets, p_slot );
- p_slot = NULL;
- p_mp4->b_sps = 1;
- }
- break;
-
- // pps
- case 0x08:
- if( !p_mp4->b_pps )
- {
- p_slot = malloc( sizeof(GF_AVCConfigSlot) );
- if( !p_slot )
- return -1;
- p_slot->size = i_size - 4;
- p_slot->data = malloc( p_slot->size );
- if( !p_slot->data )
- return -1;
- memcpy( p_slot->data, p_nalu + 4, i_size - 4 );
- gf_list_add( p_mp4->p_config->pictureParameterSets, p_slot );
- p_slot = NULL;
- p_mp4->b_pps = 1;
- if( p_mp4->b_sps )
- gf_isom_avc_config_update( p_mp4->p_file, p_mp4->i_track, 1, p_mp4->p_config );
- }
- break;
-
- // slice, sei
- case 0x1:
- case 0x5:
- case 0x6:
- psize = i_size - 4 ;
- memcpy( p_mp4->p_sample->data + p_mp4->p_sample->dataLength, p_nalu, i_size );
- p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 0] = psize >> 24;
- p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 1] = psize >> 16;
- p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 2] = psize >> 8;
- p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 3] = psize >> 0;
- p_mp4->p_sample->dataLength += i_size;
- break;
- }
-
- return i_size;
-}
-
-int set_eop_mp4( hnd_t handle, x264_picture_t *p_picture )
-{
- mp4_t *p_mp4 = (mp4_t*)handle;
- uint64_t dts = (uint64_t)p_mp4->i_numframe * p_mp4->i_time_inc;
- uint64_t pts = (uint64_t)p_picture->i_pts;
- int32_t offset = p_mp4->i_init_delay + pts - dts;
-
- p_mp4->p_sample->IsRAP = p_picture->i_type == X264_TYPE_IDR ? 1 : 0;
- p_mp4->p_sample->DTS = dts;
- p_mp4->p_sample->CTS_Offset = offset;
- gf_isom_add_sample( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx, p_mp4->p_sample );
-
- p_mp4->p_sample->dataLength = 0;
- p_mp4->i_numframe++;
-
- return 0;
-}
-
-#endif
-
-
-/* -- mkv muxing support ------------------------------------------------- */
-typedef struct
-{
- mk_writer *w;
-
- uint8_t *sps, *pps;
- int sps_len, pps_len;
-
- int width, height, d_width, d_height;
-
- int64_t frame_duration;
- int fps_num;
-
- int b_header_written;
- char b_writing_frame;
-} mkv_t;
-
-static int write_header_mkv( mkv_t *p_mkv )
-{
- int ret;
- uint8_t *avcC;
- int avcC_len;
-
- if( !p_mkv->sps || !p_mkv->pps ||
- !p_mkv->width || !p_mkv->height ||
- !p_mkv->d_width || !p_mkv->d_height )
- return -1;
-
- avcC_len = 5 + 1 + 2 + p_mkv->sps_len + 1 + 2 + p_mkv->pps_len;
- avcC = malloc( avcC_len );
- if( !avcC )
- return -1;
-
- avcC[0] = 1;
- avcC[1] = p_mkv->sps[1];
- avcC[2] = p_mkv->sps[2];
- avcC[3] = p_mkv->sps[3];
- avcC[4] = 0xff; // nalu size length is four bytes
- avcC[5] = 0xe1; // one sps
-
- avcC[6] = p_mkv->sps_len >> 8;
- avcC[7] = p_mkv->sps_len;
-
- memcpy( avcC+8, p_mkv->sps, p_mkv->sps_len );
-
- avcC[8+p_mkv->sps_len] = 1; // one pps
- avcC[9+p_mkv->sps_len] = p_mkv->pps_len >> 8;
- avcC[10+p_mkv->sps_len] = p_mkv->pps_len;
-
- memcpy( avcC+11+p_mkv->sps_len, p_mkv->pps, p_mkv->pps_len );
-
- ret = mk_writeHeader( p_mkv->w, "x264", "V_MPEG4/ISO/AVC",
- avcC, avcC_len, p_mkv->frame_duration, 50000,
- p_mkv->width, p_mkv->height,
- p_mkv->d_width, p_mkv->d_height );
-
- free( avcC );
-
- p_mkv->b_header_written = 1;
-
- return ret;
-}
-
-int open_file_mkv( char *psz_filename, hnd_t *p_handle )
-{
- mkv_t *p_mkv;
-
- *p_handle = NULL;
-
- p_mkv = malloc( sizeof(*p_mkv) );
- if( !p_mkv )
- return -1;
-
- memset( p_mkv, 0, sizeof(*p_mkv) );
-
- p_mkv->w = mk_create_writer( psz_filename );
- if( !p_mkv->w )
- {
- free( p_mkv );
- return -1;
- }
-
- *p_handle = p_mkv;
-
- return 0;
-}
-
-int set_param_mkv( hnd_t handle, x264_param_t *p_param )
-{
- mkv_t *p_mkv = handle;
- int64_t dw, dh;
-
- if( p_param->i_fps_num > 0 )
- {
- p_mkv->frame_duration = (int64_t)p_param->i_fps_den *
- (int64_t)1000000000 / p_param->i_fps_num;
- p_mkv->fps_num = p_param->i_fps_num;
- }
- else
- {
- p_mkv->frame_duration = 0;
- p_mkv->fps_num = 1;
- }
-
- p_mkv->width = p_param->i_width;
- p_mkv->height = p_param->i_height;
-
- if( p_param->vui.i_sar_width && p_param->vui.i_sar_height )
- {
- dw = (int64_t)p_param->i_width * p_param->vui.i_sar_width;
- dh = (int64_t)p_param->i_height * p_param->vui.i_sar_height;
- }
- else
- {
- dw = p_param->i_width;
- dh = p_param->i_height;
- }
-
- if( dw > 0 && dh > 0 )
- {
- int64_t x = gcd( dw, dh );
- dw /= x;
- dh /= x;
- }
-
- p_mkv->d_width = (int)dw;
- p_mkv->d_height = (int)dh;
-
- return 0;
-}
-
-int write_nalu_mkv( hnd_t handle, uint8_t *p_nalu, int i_size )
-{
- mkv_t *p_mkv = handle;
- uint8_t type = p_nalu[4] & 0x1f;
- uint8_t dsize[4];
- int psize;
-
- switch( type )
- {
- // sps
- case 0x07:
- if( !p_mkv->sps )
- {
- p_mkv->sps = malloc( i_size - 4 );
- if( !p_mkv->sps )
- return -1;
- p_mkv->sps_len = i_size - 4;
- memcpy( p_mkv->sps, p_nalu + 4, i_size - 4 );
- }
- break;
-
- // pps
- case 0x08:
- if( !p_mkv->pps )
- {
- p_mkv->pps = malloc( i_size - 4 );
- if( !p_mkv->pps )
- return -1;
- p_mkv->pps_len = i_size - 4;
- memcpy( p_mkv->pps, p_nalu + 4, i_size - 4 );
- }
- break;
-
- // slice, sei
- case 0x1:
- case 0x5:
- case 0x6:
- if( !p_mkv->b_writing_frame )
- {
- if( mk_start_frame( p_mkv->w ) < 0 )
- return -1;
- p_mkv->b_writing_frame = 1;
- }
- psize = i_size - 4 ;
- dsize[0] = psize >> 24;
- dsize[1] = psize >> 16;
- dsize[2] = psize >> 8;
- dsize[3] = psize;
- if( mk_add_frame_data( p_mkv->w, dsize, 4 ) < 0 ||
- mk_add_frame_data( p_mkv->w, p_nalu + 4, i_size - 4 ) < 0 )
- return -1;
- break;
-
- default:
- break;
- }
-
- if( !p_mkv->b_header_written && p_mkv->pps && p_mkv->sps &&
- write_header_mkv( p_mkv ) < 0 )
- return -1;
-
- return i_size;
-}
-
-int set_eop_mkv( hnd_t handle, x264_picture_t *p_picture )
-{
- mkv_t *p_mkv = handle;
- int64_t i_stamp = (int64_t)(p_picture->i_pts * 1e9 / p_mkv->fps_num);
-
- p_mkv->b_writing_frame = 0;
-
- return mk_set_frame_flags( p_mkv->w, i_stamp, p_picture->i_type == X264_TYPE_IDR );
-}
-
-int close_file_mkv( hnd_t handle )
-{
- mkv_t *p_mkv = handle;
- int ret;
-
- if( p_mkv->sps )
- free( p_mkv->sps );
- if( p_mkv->pps )
- free( p_mkv->pps );
-
- ret = mk_close( p_mkv->w );
-
- free( p_mkv );
-
- return ret;
-}
-
/*****************************************************************************
- * muxers.c: h264 file i/o plugins
+ * muxers.h: h264 file i/o modules
*****************************************************************************
- * Copyright (C) 2003-2008 x264 project
+ * Copyright (C) 2003-2009 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
#ifndef X264_MUXERS_H
#define X264_MUXERS_H
-typedef void *hnd_t;
-
-int open_file_yuv( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
-int get_frame_total_yuv( hnd_t handle );
-int read_frame_yuv( x264_picture_t *p_pic, hnd_t handle, int i_frame );
-int close_file_yuv( hnd_t handle );
-
-int open_file_y4m( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
-int get_frame_total_y4m( hnd_t handle );
-int read_frame_y4m( x264_picture_t *p_pic, hnd_t handle, int i_frame );
-int close_file_y4m( hnd_t handle );
-
-int open_file_avis( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
-int get_frame_total_avis( hnd_t handle );
-int read_frame_avis( x264_picture_t *p_pic, hnd_t handle, int i_frame );
-int close_file_avis( hnd_t handle );
+#include "common/common.h"
+#include "x264.h"
-int open_file_thread( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
-int get_frame_total_thread( hnd_t handle );
-int read_frame_thread( x264_picture_t *p_pic, hnd_t handle, int i_frame );
-int close_file_thread( hnd_t handle );
-
-int open_file_bsf( char *psz_filename, hnd_t *p_handle );
-int set_param_bsf( hnd_t handle, x264_param_t *p_param );
-int write_nalu_bsf( hnd_t handle, uint8_t *p_nal, int i_size );
-int set_eop_bsf( hnd_t handle, x264_picture_t *p_picture );
-int close_file_bsf( hnd_t handle );
-
-int open_file_mp4( char *psz_filename, hnd_t *p_handle );
-int set_param_mp4( hnd_t handle, x264_param_t *p_param );
-int write_nalu_mp4( hnd_t handle, uint8_t *p_nal, int i_size );
-int set_eop_mp4( hnd_t handle, x264_picture_t *p_picture );
-int close_file_mp4( hnd_t handle );
-
-int open_file_mkv( char *psz_filename, hnd_t *p_handle );
-int set_param_mkv( hnd_t handle, x264_param_t *p_param );
-int write_nalu_mkv( hnd_t handle, uint8_t *p_nal, int i_size );
-int set_eop_mkv( hnd_t handle, x264_picture_t *p_picture );
-int close_file_mkv( hnd_t handle );
+typedef void *hnd_t;
-extern int (*p_open_infile)( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
-extern int (*p_get_frame_total)( hnd_t handle );
-extern int (*p_read_frame)( x264_picture_t *p_pic, hnd_t handle, int i_frame );
-extern int (*p_close_infile)( hnd_t handle );
+static inline int64_t gcd( int64_t a, int64_t b )
+{
+ while( 1 )
+ {
+ int64_t c = a % b;
+ if( !c )
+ return b;
+ a = b;
+ b = c;
+ }
+}
+
+#include "input/input.h"
+#include "output/output.h"
#endif
--- /dev/null
+/*****************************************************************************
+ * matroska.c: x264 matroska output module
+ *****************************************************************************
+ * Copyright (C) 2005 Mike Matsnev
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#include "muxers.h"
+#include "matroska_ebml.h"
+
+typedef struct
+{
+ mk_writer *w;
+
+ uint8_t *sps, *pps;
+ int sps_len, pps_len;
+
+ int width, height, d_width, d_height;
+
+ int64_t frame_duration;
+ int fps_num;
+
+ int b_header_written;
+ char b_writing_frame;
+} mkv_hnd_t;
+
+static int write_header( mkv_hnd_t *p_mkv )
+{
+ int ret;
+ uint8_t *avcC;
+ int avcC_len;
+
+ if( !p_mkv->sps || !p_mkv->pps ||
+ !p_mkv->width || !p_mkv->height ||
+ !p_mkv->d_width || !p_mkv->d_height )
+ return -1;
+
+ avcC_len = 5 + 1 + 2 + p_mkv->sps_len + 1 + 2 + p_mkv->pps_len;
+ avcC = malloc( avcC_len );
+ if( !avcC )
+ return -1;
+
+ avcC[0] = 1;
+ avcC[1] = p_mkv->sps[1];
+ avcC[2] = p_mkv->sps[2];
+ avcC[3] = p_mkv->sps[3];
+ avcC[4] = 0xff; // nalu size length is four bytes
+ avcC[5] = 0xe1; // one sps
+
+ avcC[6] = p_mkv->sps_len >> 8;
+ avcC[7] = p_mkv->sps_len;
+
+ memcpy( avcC+8, p_mkv->sps, p_mkv->sps_len );
+
+ avcC[8+p_mkv->sps_len] = 1; // one pps
+ avcC[9+p_mkv->sps_len] = p_mkv->pps_len >> 8;
+ avcC[10+p_mkv->sps_len] = p_mkv->pps_len;
+
+ memcpy( avcC+11+p_mkv->sps_len, p_mkv->pps, p_mkv->pps_len );
+
+ ret = mk_writeHeader( p_mkv->w, "x264", "V_MPEG4/ISO/AVC",
+ avcC, avcC_len, p_mkv->frame_duration, 50000,
+ p_mkv->width, p_mkv->height,
+ p_mkv->d_width, p_mkv->d_height );
+
+ free( avcC );
+
+ p_mkv->b_header_written = 1;
+
+ return ret;
+}
+
+static int open_file( char *psz_filename, hnd_t *p_handle )
+{
+ mkv_hnd_t *p_mkv;
+
+ *p_handle = NULL;
+
+ p_mkv = malloc( sizeof(*p_mkv) );
+ if( !p_mkv )
+ return -1;
+
+ memset( p_mkv, 0, sizeof(*p_mkv) );
+
+ p_mkv->w = mk_create_writer( psz_filename );
+ if( !p_mkv->w )
+ {
+ free( p_mkv );
+ return -1;
+ }
+
+ *p_handle = p_mkv;
+
+ return 0;
+}
+
+static int set_param( hnd_t handle, x264_param_t *p_param )
+{
+ mkv_hnd_t *p_mkv = handle;
+ int64_t dw, dh;
+
+ if( p_param->i_fps_num > 0 )
+ {
+ p_mkv->frame_duration = (int64_t)p_param->i_fps_den *
+ (int64_t)1000000000 / p_param->i_fps_num;
+ p_mkv->fps_num = p_param->i_fps_num;
+ }
+ else
+ {
+ p_mkv->frame_duration = 0;
+ p_mkv->fps_num = 1;
+ }
+
+ p_mkv->width = p_param->i_width;
+ p_mkv->height = p_param->i_height;
+
+ if( p_param->vui.i_sar_width && p_param->vui.i_sar_height )
+ {
+ dw = (int64_t)p_param->i_width * p_param->vui.i_sar_width;
+ dh = (int64_t)p_param->i_height * p_param->vui.i_sar_height;
+ }
+ else
+ {
+ dw = p_param->i_width;
+ dh = p_param->i_height;
+ }
+
+ if( dw > 0 && dh > 0 )
+ {
+ int64_t x = gcd( dw, dh );
+ dw /= x;
+ dh /= x;
+ }
+
+ p_mkv->d_width = (int)dw;
+ p_mkv->d_height = (int)dh;
+
+ return 0;
+}
+
+static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size )
+{
+ mkv_hnd_t *p_mkv = handle;
+ uint8_t type = p_nalu[4] & 0x1f;
+ uint8_t dsize[4];
+ int psize;
+
+ switch( type )
+ {
+ // sps
+ case 0x07:
+ if( !p_mkv->sps )
+ {
+ p_mkv->sps = malloc( i_size - 4 );
+ if( !p_mkv->sps )
+ return -1;
+ p_mkv->sps_len = i_size - 4;
+ memcpy( p_mkv->sps, p_nalu + 4, i_size - 4 );
+ }
+ break;
+
+ // pps
+ case 0x08:
+ if( !p_mkv->pps )
+ {
+ p_mkv->pps = malloc( i_size - 4 );
+ if( !p_mkv->pps )
+ return -1;
+ p_mkv->pps_len = i_size - 4;
+ memcpy( p_mkv->pps, p_nalu + 4, i_size - 4 );
+ }
+ break;
+
+ // slice, sei
+ case 0x1:
+ case 0x5:
+ case 0x6:
+ if( !p_mkv->b_writing_frame )
+ {
+ if( mk_start_frame( p_mkv->w ) < 0 )
+ return -1;
+ p_mkv->b_writing_frame = 1;
+ }
+ psize = i_size - 4;
+ dsize[0] = psize >> 24;
+ dsize[1] = psize >> 16;
+ dsize[2] = psize >> 8;
+ dsize[3] = psize;
+ if( mk_add_frame_data( p_mkv->w, dsize, 4 ) < 0 ||
+ mk_add_frame_data( p_mkv->w, p_nalu + 4, i_size - 4 ) < 0 )
+ return -1;
+ break;
+
+ default:
+ break;
+ }
+
+ if( !p_mkv->b_header_written && p_mkv->pps && p_mkv->sps &&
+ write_header( p_mkv ) < 0 )
+ return -1;
+
+ return i_size;
+}
+
+static int set_eop( hnd_t handle, x264_picture_t *p_picture )
+{
+ mkv_hnd_t *p_mkv = handle;
+ int64_t i_stamp = (int64_t)(p_picture->i_pts * 1e9 / p_mkv->fps_num);
+
+ p_mkv->b_writing_frame = 0;
+
+ return mk_set_frame_flags( p_mkv->w, i_stamp, p_picture->i_type == X264_TYPE_IDR );
+}
+
+static int close_file( hnd_t handle )
+{
+ mkv_hnd_t *p_mkv = handle;
+ int ret;
+
+ if( p_mkv->sps )
+ free( p_mkv->sps );
+ if( p_mkv->pps )
+ free( p_mkv->pps );
+
+ ret = mk_close( p_mkv->w );
+
+ free( p_mkv );
+
+ return ret;
+}
+
+cli_output_t mkv_output = { open_file, set_param, write_nalu, set_eop, close_file };
/*****************************************************************************
- * matroska.c:
+ * matroska_ebml.c:
*****************************************************************************
* Copyright (C) 2005 Mike Matsnev
*
#include <stdlib.h>
#include <string.h>
#include "common/osdep.h"
-#include "matroska.h"
+#include "matroska_ebml.h"
#define CLSIZE 1048576
#define CHECK(x)\
-do\
-{\
- if( (x) < 0 ) return -1;\
-}\
-while( 0 )
+do {\
+ if( (x) < 0 )\
+ return -1;\
+} while( 0 )
struct mk_context
{
struct mk_context *next, **prev, *parent;
- struct mk_writer *owner;
+ mk_writer *owner;
unsigned id;
void *data;
static mk_context *mk_create_context( mk_writer *w, mk_context *parent, unsigned id )
{
- mk_context *c;
+ mk_context *c;
if( w->freelist )
{
return 0;
}
-static int mk_flush_context_data(mk_context *c)
+static int mk_flush_context_data( mk_context *c )
{
if( !c->d_cur )
return 0;
return 0;
}
-static int mk_close_context(mk_context *c, unsigned *off)
+static int mk_close_context( mk_context *c, unsigned *off )
{
if( c->id )
{
w->timescale = timescale;
w->def_duration = default_frame_duration;
- if( !(c = mk_create_context(w, w->root, 0x1a45dfa3)) ) // EBML
+ if( !(c = mk_create_context( w, w->root, 0x1a45dfa3 )) ) // EBML
return -1;
CHECK( mk_write_uint( c, 0x4286, 1 ) ); // EBMLVersion
CHECK( mk_write_uint( c, 0x42f7, 1 ) ); // EBMLReadVersion
CHECK( mk_flush_context_id( c ) );
CHECK( mk_close_context( c, 0 ) );
- if( !(c = mk_create_context(w, w->root, 0x1549a966)) ) // SegmentInfo
+ if( !(c = mk_create_context( w, w->root, 0x1549a966 )) ) // SegmentInfo
return -1;
CHECK( mk_write_string( c, 0x4d80, "Haali Matroska Writer b0" ) );
CHECK( mk_write_string( c, 0x5741, writing_app ) );
CHECK( mk_append_context_data( w->cluster, c_delta_flags, 3 ) );
if( w->frame )
{
- CHECK( mk_append_context_data(w->cluster, w->frame->data, w->frame->d_cur));
+ CHECK( mk_append_context_data( w->cluster, w->frame->data, w->frame->d_cur ) );
w->frame->d_cur = 0;
}
if( !w->keyframe )
- CHECK( mk_write_sint(w->cluster, 0xfb, ref ) ); // ReferenceBlock
+ CHECK( mk_write_sint( w->cluster, 0xfb, ref ) ); // ReferenceBlock
w->in_frame = 0;
w->prev_frame_tc_scaled = w->cluster_tc_scaled + delta;
return 0;
}
-int mk_set_frame_flags( mk_writer *w,int64_t timestamp, int keyframe )
+int mk_set_frame_flags( mk_writer *w, int64_t timestamp, int keyframe )
{
if( !w->in_frame )
return -1;
if( !(w->frame = mk_create_context( w, NULL, 0 )) )
return -1;
- return mk_append_context_data( w->frame, data, size );
+ return mk_append_context_data( w->frame, data, size );
}
int mk_close( mk_writer *w )
{
fseek( w->fp, w->duration_ptr, SEEK_SET );
if( mk_write_float_raw( w->root, (float)((double)(w->max_frame_tc+w->def_duration) / w->timescale) ) < 0 ||
- mk_flush_context_data(w->root) < 0 )
+ mk_flush_context_data( w->root ) < 0 )
ret = -1;
}
mk_destroy_contexts( w );
free( w );
return ret;
}
-
/*****************************************************************************
- * matroska.h:
+ * matroska_ebml.h:
*****************************************************************************
* Copyright (C) 2005 Mike Matsnev
*
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*****************************************************************************/
-#ifndef X264_MATROSKA_H
-#define X264_MATROSKA_H
+#ifndef X264_MATROSKA_EBML_H
+#define X264_MATROSKA_EBML_H
typedef struct mk_writer mk_writer;
unsigned width, unsigned height,
unsigned d_width, unsigned d_height );
-int mk_start_frame( mk_writer *w );
-int mk_add_frame_data( mk_writer *w, const void *data, unsigned size );
-int mk_set_frame_flags( mk_writer *w, int64_t timestamp, int keyframe );
-int mk_close( mk_writer *w );
+int mk_start_frame( mk_writer *w );
+int mk_add_frame_data( mk_writer *w, const void *data, unsigned size );
+int mk_set_frame_flags( mk_writer *w, int64_t timestamp, int keyframe );
+int mk_close( mk_writer *w );
#endif
--- /dev/null
+/*****************************************************************************
+ * mp4.c: x264 mp4 output module
+ *****************************************************************************
+ * Copyright (C) 2003-2009 x264 project
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * Loren Merritt <lorenm@u.washington.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#include "muxers.h"
+#include <gpac/isomedia.h>
+
+typedef struct
+{
+ GF_ISOFile *p_file;
+ GF_AVCConfig *p_config;
+ GF_ISOSample *p_sample;
+ int i_track;
+ uint32_t i_descidx;
+ int i_time_inc;
+ int i_time_res;
+ int i_numframe;
+ int i_init_delay;
+ uint8_t b_sps;
+ uint8_t b_pps;
+} mp4_hnd_t;
+
+static void recompute_bitrate_mp4( GF_ISOFile *p_file, int i_track )
+{
+ u32 i, count, di, timescale, time_wnd, rate;
+ u64 offset;
+ Double br;
+ GF_ESD *esd;
+
+ esd = gf_isom_get_esd( p_file, i_track, 1 );
+ if( !esd )
+ return;
+
+ esd->decoderConfig->avgBitrate = 0;
+ esd->decoderConfig->maxBitrate = 0;
+ rate = time_wnd = 0;
+
+ timescale = gf_isom_get_media_timescale( p_file, i_track );
+ count = gf_isom_get_sample_count( p_file, i_track );
+ for( i = 0; i < count; i++ )
+ {
+ GF_ISOSample *samp = gf_isom_get_sample_info( p_file, i_track, i+1, &di, &offset );
+
+ if( samp->dataLength>esd->decoderConfig->bufferSizeDB )
+ esd->decoderConfig->bufferSizeDB = samp->dataLength;
+
+ if( esd->decoderConfig->bufferSizeDB < samp->dataLength )
+ esd->decoderConfig->bufferSizeDB = samp->dataLength;
+
+ esd->decoderConfig->avgBitrate += samp->dataLength;
+ rate += samp->dataLength;
+ if( samp->DTS > time_wnd + timescale )
+ {
+ if( rate > esd->decoderConfig->maxBitrate )
+ esd->decoderConfig->maxBitrate = rate;
+ time_wnd = samp->DTS;
+ rate = 0;
+ }
+
+ gf_isom_sample_del( &samp );
+ }
+
+ br = (Double)(s64)gf_isom_get_media_duration( p_file, i_track );
+ br /= timescale;
+ esd->decoderConfig->avgBitrate = (u32)(esd->decoderConfig->avgBitrate / br);
+ /*move to bps*/
+ esd->decoderConfig->avgBitrate *= 8;
+ esd->decoderConfig->maxBitrate *= 8;
+
+ gf_isom_change_mpeg4_description( p_file, i_track, 1, esd );
+ gf_odf_desc_del( (GF_Descriptor*)esd );
+}
+
+static int close_file( hnd_t handle )
+{
+ mp4_hnd_t *p_mp4 = handle;
+
+ if( !p_mp4 )
+ return 0;
+
+ if( p_mp4->p_config )
+ gf_odf_avc_cfg_del( p_mp4->p_config );
+
+ if( p_mp4->p_sample )
+ {
+ if( p_mp4->p_sample->data )
+ free( p_mp4->p_sample->data );
+
+ gf_isom_sample_del( &p_mp4->p_sample );
+ }
+
+ if( p_mp4->p_file )
+ {
+ recompute_bitrate_mp4( p_mp4->p_file, p_mp4->i_track );
+ gf_isom_set_pl_indication( p_mp4->p_file, GF_ISOM_PL_VISUAL, 0x15 );
+ gf_isom_set_storage_mode( p_mp4->p_file, GF_ISOM_STORE_FLAT );
+ gf_isom_close( p_mp4->p_file );
+ }
+
+ free( p_mp4 );
+
+ return 0;
+}
+
+static int open_file( char *psz_filename, hnd_t *p_handle )
+{
+ mp4_hnd_t *p_mp4;
+
+ *p_handle = NULL;
+
+ if( !(p_mp4 = malloc( sizeof(mp4_hnd_t) )) )
+ return -1;
+
+ memset( p_mp4, 0, sizeof(mp4_hnd_t) );
+ p_mp4->p_file = gf_isom_open( psz_filename, GF_ISOM_OPEN_WRITE, NULL );
+
+ if( !(p_mp4->p_sample = gf_isom_sample_new()) )
+ {
+ close_file( p_mp4 );
+ return -1;
+ }
+
+ gf_isom_set_brand_info( p_mp4->p_file, GF_ISOM_BRAND_AVC1, 0 );
+
+ *p_handle = p_mp4;
+
+ return 0;
+}
+
+static int set_param( hnd_t handle, x264_param_t *p_param )
+{
+ mp4_hnd_t *p_mp4 = handle;
+
+ p_mp4->i_track = gf_isom_new_track( p_mp4->p_file, 0, GF_ISOM_MEDIA_VISUAL,
+ p_param->i_fps_num );
+
+ p_mp4->p_config = gf_odf_avc_cfg_new();
+ gf_isom_avc_config_new( p_mp4->p_file, p_mp4->i_track, p_mp4->p_config,
+ NULL, NULL, &p_mp4->i_descidx );
+
+ gf_isom_set_track_enabled( p_mp4->p_file, p_mp4->i_track, 1 );
+
+ gf_isom_set_visual_info( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx,
+ p_param->i_width, p_param->i_height );
+
+ if( p_param->vui.i_sar_width && p_param->vui.i_sar_height )
+ {
+ uint64_t dw = p_param->i_width << 16;
+ uint64_t dh = p_param->i_height << 16;
+ double sar = (double)p_param->vui.i_sar_width / p_param->vui.i_sar_height;
+ if( sar > 1.0 )
+ dw *= sar ;
+ else
+ dh /= sar;
+ gf_isom_set_track_layout_info( p_mp4->p_file, p_mp4->i_track, dw, dh, 0, 0, 0 );
+ }
+
+ p_mp4->p_sample->data = malloc( p_param->i_width * p_param->i_height * 3 / 2 );
+ if( !p_mp4->p_sample->data )
+ return -1;
+
+ p_mp4->i_time_res = p_param->i_fps_num;
+ p_mp4->i_time_inc = p_param->i_fps_den;
+ p_mp4->i_init_delay = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0;
+ p_mp4->i_init_delay *= p_mp4->i_time_inc;
+ fprintf( stderr, "mp4 [info]: initial delay %d (scale %d)\n",
+ p_mp4->i_init_delay, p_mp4->i_time_res );
+
+ return 0;
+}
+
+static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size )
+{
+ mp4_hnd_t *p_mp4 = handle;
+ GF_AVCConfigSlot *p_slot;
+ uint8_t type = p_nalu[4] & 0x1f;
+ int psize;
+
+ switch( type )
+ {
+ // sps
+ case 0x07:
+ if( !p_mp4->b_sps )
+ {
+ p_mp4->p_config->configurationVersion = 1;
+ p_mp4->p_config->AVCProfileIndication = p_nalu[5];
+ p_mp4->p_config->profile_compatibility = p_nalu[6];
+ p_mp4->p_config->AVCLevelIndication = p_nalu[7];
+ p_slot = malloc( sizeof(GF_AVCConfigSlot) );
+ if( !p_slot )
+ return -1;
+ p_slot->size = i_size - 4;
+ p_slot->data = malloc( p_slot->size );
+ if( !p_slot->data )
+ return -1;
+ memcpy( p_slot->data, p_nalu + 4, i_size - 4 );
+ gf_list_add( p_mp4->p_config->sequenceParameterSets, p_slot );
+ p_slot = NULL;
+ p_mp4->b_sps = 1;
+ }
+ break;
+
+ // pps
+ case 0x08:
+ if( !p_mp4->b_pps )
+ {
+ p_slot = malloc( sizeof(GF_AVCConfigSlot) );
+ if( !p_slot )
+ return -1;
+ p_slot->size = i_size - 4;
+ p_slot->data = malloc( p_slot->size );
+ if( !p_slot->data )
+ return -1;
+ memcpy( p_slot->data, p_nalu + 4, i_size - 4 );
+ gf_list_add( p_mp4->p_config->pictureParameterSets, p_slot );
+ p_slot = NULL;
+ p_mp4->b_pps = 1;
+ if( p_mp4->b_sps )
+ gf_isom_avc_config_update( p_mp4->p_file, p_mp4->i_track, 1, p_mp4->p_config );
+ }
+ break;
+
+ // slice, sei
+ case 0x1:
+ case 0x5:
+ case 0x6:
+ psize = i_size - 4;
+ memcpy( p_mp4->p_sample->data + p_mp4->p_sample->dataLength, p_nalu, i_size );
+ p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 0] = psize >> 24;
+ p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 1] = psize >> 16;
+ p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 2] = psize >> 8;
+ p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 3] = psize >> 0;
+ p_mp4->p_sample->dataLength += i_size;
+ break;
+ }
+
+ return i_size;
+}
+
+static int set_eop( hnd_t handle, x264_picture_t *p_picture )
+{
+ mp4_hnd_t *p_mp4 = handle;
+ uint64_t dts = (uint64_t)p_mp4->i_numframe * p_mp4->i_time_inc;
+ uint64_t pts = (uint64_t)p_picture->i_pts;
+ int32_t offset = p_mp4->i_init_delay + pts - dts;
+
+ p_mp4->p_sample->IsRAP = p_picture->i_type == X264_TYPE_IDR ? 1 : 0;
+ p_mp4->p_sample->DTS = dts;
+ p_mp4->p_sample->CTS_Offset = offset;
+ gf_isom_add_sample( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx, p_mp4->p_sample );
+
+ p_mp4->p_sample->dataLength = 0;
+ p_mp4->i_numframe++;
+
+ return 0;
+}
+
+cli_output_t mp4_output = { open_file, set_param, write_nalu, set_eop, close_file };
--- /dev/null
+/*****************************************************************************
+ * output.h: x264 file output modules
+ *****************************************************************************
+ * Copyright (C) 2003-2009 x264 project
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * Loren Merritt <lorenm@u.washington.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#ifndef X264_OUTPUT_H
+#define X264_OUTPUT_H
+
+typedef struct
+{
+ int (*open_file)( char *psz_filename, hnd_t *p_handle );
+ int (*set_param)( hnd_t handle, x264_param_t *p_param );
+ int (*write_nalu)( hnd_t handle, uint8_t *p_nal, int i_size );
+ int (*set_eop)( hnd_t handle, x264_picture_t *p_picture );
+ int (*close_file)( hnd_t handle );
+} cli_output_t;
+
+extern cli_output_t raw_output;
+extern cli_output_t mkv_output;
+extern cli_output_t mp4_output;
+
+#endif
--- /dev/null
+/*****************************************************************************
+ * raw.c: x264 raw bitstream output module
+ *****************************************************************************
+ * Copyright (C) 2003-2009 x264 project
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * Loren Merritt <lorenm@u.washington.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#include "muxers.h"
+
+static int open_file( char *psz_filename, hnd_t *p_handle )
+{
+ if( !(*p_handle = fopen( psz_filename, "w+b" )) )
+ return -1;
+
+ return 0;
+}
+
+static int set_param( hnd_t handle, x264_param_t *p_param )
+{
+ return 0;
+}
+
+static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size )
+{
+ if( fwrite( p_nalu, i_size, 1, (FILE*)handle ) > 0 )
+ return i_size;
+ return -1;
+}
+
+static int set_eop( hnd_t handle, x264_picture_t *p_picture )
+{
+ return 0;
+}
+
+static int close_file( hnd_t handle )
+{
+ if( !handle || handle == stdout )
+ return 0;
+
+ return fclose( (FILE*)handle );
+}
+
+cli_output_t raw_output = { open_file, set_param, write_nalu, set_eop, close_file };
FILE *qpfile;
} cli_opt_t;
-/* input file operation function pointers */
-int (*p_open_infile)( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
-int (*p_get_frame_total)( hnd_t handle );
-int (*p_read_frame)( x264_picture_t *p_pic, hnd_t handle, int i_frame );
-int (*p_close_infile)( hnd_t handle );
-
-/* output file operation function pointers */
-static int (*p_open_outfile)( char *psz_filename, hnd_t *p_handle );
-static int (*p_set_outfile_param)( hnd_t handle, x264_param_t *p_param );
-static int (*p_write_nalu)( hnd_t handle, uint8_t *p_nal, int i_size );
-static int (*p_set_eop)( hnd_t handle, x264_picture_t *p_picture );
-static int (*p_close_outfile)( hnd_t handle );
+/* i/o file operation function pointer structs */
+cli_input_t input;
+static cli_output_t output;
static void Help( x264_param_t *defaults, int longhelp );
static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt );
memset( opt, 0, sizeof(cli_opt_t) );
opt->b_progress = 1;
- /* Default input file driver */
- p_open_infile = open_file_yuv;
- p_get_frame_total = get_frame_total_yuv;
- p_read_frame = read_frame_yuv;
- p_close_infile = close_file_yuv;
-
- /* Default output file driver */
- p_open_outfile = open_file_bsf;
- p_set_outfile_param = set_param_bsf;
- p_write_nalu = write_nalu_bsf;
- p_set_eop = set_eop_bsf;
- p_close_outfile = close_file_bsf;
+ /* Default i/o modules */
+ input = yuv_input;
+ output = raw_output;
/* Presets are applied before all other options. */
for( optind = 0;; )
if( !strncasecmp(optarg + strlen(optarg) - 4, ".mp4", 4) )
{
#ifdef MP4_OUTPUT
- p_open_outfile = open_file_mp4;
- p_write_nalu = write_nalu_mp4;
- p_set_outfile_param = set_param_mp4;
- p_set_eop = set_eop_mp4;
- p_close_outfile = close_file_mp4;
+ output = mp4_output;
#else
fprintf( stderr, "x264 [error]: not compiled with MP4 output support\n" );
return -1;
#endif
}
else if( !strncasecmp(optarg + strlen(optarg) - 4, ".mkv", 4) )
- {
- p_open_outfile = open_file_mkv;
- p_write_nalu = write_nalu_mkv;
- p_set_outfile_param = set_param_mkv;
- p_set_eop = set_eop_mkv;
- p_close_outfile = close_file_mkv;
- }
+ output = mkv_output;
if( !strcmp(optarg, "-") )
opt->hout = stdout;
- else if( p_open_outfile( optarg, &opt->hout ) )
+ else if( output.open_file( optarg, &opt->hout ) )
{
fprintf( stderr, "x264 [error]: can't open output file `%s'\n", optarg );
return -1;
if( b_avis )
{
#ifdef AVIS_INPUT
- p_open_infile = open_file_avis;
- p_get_frame_total = get_frame_total_avis;
- p_read_frame = read_frame_avis;
- p_close_infile = close_file_avis;
+ input = avis_input;
#else
fprintf( stderr, "x264 [error]: not compiled with AVIS input support\n" );
return -1;
#endif
}
if( b_y4m )
- {
- p_open_infile = open_file_y4m;
- p_get_frame_total = get_frame_total_y4m;
- p_read_frame = read_frame_y4m;
- p_close_infile = close_file_y4m;
- }
+ input = y4m_input;
- if( p_open_infile( psz_filename, &opt->hin, param ) )
+ if( input.open_file( psz_filename, &opt->hin, param ) )
{
fprintf( stderr, "x264 [error]: could not open input file '%s'\n", psz_filename );
return -1;
if( b_thread_input || param->i_threads > 1
|| (param->i_threads == X264_THREADS_AUTO && x264_cpu_num_processors() > 1) )
{
- if( open_file_thread( NULL, &opt->hin, param ) )
+ if( thread_input.open_file( NULL, &opt->hin, param ) )
{
fprintf( stderr, "x264 [error]: threaded input failed\n" );
return -1;
}
else
- {
- p_open_infile = open_file_thread;
- p_get_frame_total = get_frame_total_thread;
- p_read_frame = read_frame_thread;
- p_close_infile = close_file_thread;
- }
+ input = thread_input;
}
#endif
for( i = 0; i < i_nal; i++ )
{
- i_nalu_size = p_write_nalu( hout, nal[i].p_payload, nal[i].i_payload );
+ i_nalu_size = output.write_nalu( hout, nal[i].p_payload, nal[i].i_payload );
if( i_nalu_size < 0 )
return -1;
i_file += i_nalu_size;
}
- if (i_nal)
- p_set_eop( hout, &pic_out );
+ if( i_nal )
+ output.set_eop( hout, &pic_out );
return i_file;
}
int i_update_interval;
opt->b_progress &= param->i_log_level < X264_LOG_DEBUG;
- i_frame_total = p_get_frame_total( opt->hin );
+ i_frame_total = input.get_frame_total( opt->hin );
i_frame_total -= opt->i_seek;
if( ( i_frame_total == 0 || param->i_frame_total < i_frame_total )
&& param->i_frame_total > 0 )
if( ( h = x264_encoder_open( param ) ) == NULL )
{
fprintf( stderr, "x264 [error]: x264_encoder_open failed\n" );
- p_close_infile( opt->hin );
+ input.close_file( opt->hin );
return -1;
}
- if( p_set_outfile_param( opt->hout, param ) )
+ if( output.set_param( opt->hout, param ) )
{
fprintf( stderr, "x264 [error]: can't set outfile param\n" );
- p_close_infile( opt->hin );
- p_close_outfile( opt->hout );
+ input.close_file( opt->hin );
+ output.close_file( opt->hout );
return -1;
}
/* Encode frames */
for( i_frame = 0, i_file = 0, i_frame_output = 0; b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); )
{
- if( p_read_frame( &pic, opt->hin, i_frame + opt->i_seek ) )
+ if( input.read_frame( &pic, opt->hin, i_frame + opt->i_seek ) )
break;
pic.i_pts = (int64_t)i_frame * param->i_fps_den;
if( b_ctrl_c )
fprintf( stderr, "aborted at input frame %d, output frame %d\n", opt->i_seek + i_frame, i_frame_output );
- p_close_infile( opt->hin );
- p_close_outfile( opt->hout );
+ input.close_file( opt->hin );
+ output.close_file( opt->hout );
if( i_frame_output > 0 )
{