split muxers.c into one file per format
authorSteven Walters <kemuri9@gmail.com>
Sat, 24 Oct 2009 00:23:50 +0000 (00:23 +0000)
committerLoren Merritt <pengvado@akuvian.org>
Sat, 24 Oct 2009 00:53:38 +0000 (00:53 +0000)
simplify internal muxer API

17 files changed:
Makefile
input/avis.c [new file with mode: 0644]
input/input.h [new file with mode: 0644]
input/thread.c [new file with mode: 0644]
input/y4m.c [new file with mode: 0644]
input/yuv.c [new file with mode: 0644]
matroska.c [deleted file]
matroska.h [deleted file]
muxers.c [deleted file]
muxers.h
output/matroska.c [new file with mode: 0644]
output/matroska_ebml.c [new file with mode: 0644]
output/matroska_ebml.h [new file with mode: 0644]
output/mp4.c [new file with mode: 0644]
output/output.h [new file with mode: 0644]
output/raw.c [new file with mode: 0644]
x264.c

index 9ba29f3..3de0b61 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,23 @@ SRCS = common/mc.c common/predict.c common/pixel.c common/macroblock.c \
        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)
diff --git a/input/avis.c b/input/avis.c
new file mode 100644 (file)
index 0000000..2ca1634
--- /dev/null
@@ -0,0 +1,119 @@
+/*****************************************************************************
+ * 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 };
diff --git a/input/input.h b/input/input.h
new file mode 100644 (file)
index 0000000..87d5386
--- /dev/null
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * 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
diff --git a/input/thread.c b/input/thread.c
new file mode 100644 (file)
index 0000000..a9330dc
--- /dev/null
@@ -0,0 +1,126 @@
+/*****************************************************************************
+ * 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 };
diff --git a/input/y4m.c b/input/y4m.c
new file mode 100644 (file)
index 0000000..a04cd21
--- /dev/null
@@ -0,0 +1,232 @@
+/*****************************************************************************
+ * 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 };
diff --git a/input/yuv.c b/input/yuv.c
new file mode 100644 (file)
index 0000000..98dc46c
--- /dev/null
@@ -0,0 +1,96 @@
+/*****************************************************************************
+ * 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 };
diff --git a/matroska.c b/matroska.c
deleted file mode 100644 (file)
index 793420e..0000000
+++ /dev/null
@@ -1,561 +0,0 @@
-/*****************************************************************************
- * matroska.c:
- *****************************************************************************
- * 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 <stdlib.h>
-#include <string.h>
-#include "common/osdep.h"
-#include "matroska.h"
-
-#define CLSIZE 1048576
-#define CHECK(x)\
-do\
-{\
-    if( (x) < 0 ) return -1;\
-}\
-while( 0 )
-
-struct mk_context
-{
-    struct mk_context *next, **prev, *parent;
-    struct mk_writer *owner;
-    unsigned id;
-
-    void *data;
-    unsigned d_cur, d_max;
-};
-
-typedef struct mk_context mk_context;
-
-struct mk_writer
-{
-    FILE *fp;
-
-    unsigned duration_ptr;
-
-    mk_context *root, *cluster, *frame;
-    mk_context *freelist;
-    mk_context *actlist;
-
-    int64_t def_duration;
-    int64_t timescale;
-    int64_t cluster_tc_scaled;
-    int64_t frame_tc, prev_frame_tc_scaled, max_frame_tc;
-
-    char wrote_header, in_frame, keyframe;
-};
-
-static mk_context *mk_create_context( mk_writer *w, mk_context *parent, unsigned id )
-{
-    mk_context  *c;
-
-    if( w->freelist )
-    {
-        c = w->freelist;
-        w->freelist = w->freelist->next;
-    }
-    else
-    {
-        c = malloc( sizeof(*c) );
-        if( !c )
-            return NULL;
-        memset( c, 0, sizeof(*c) );
-    }
-
-    c->parent = parent;
-    c->owner = w;
-    c->id = id;
-
-    if( c->owner->actlist )
-        c->owner->actlist->prev = &c->next;
-    c->next = c->owner->actlist;
-    c->prev = &c->owner->actlist;
-    c->owner->actlist = c;
-
-    return c;
-}
-
-static int mk_append_context_data( mk_context *c, const void *data, unsigned size )
-{
-    unsigned ns = c->d_cur + size;
-
-    if( ns > c->d_max )
-    {
-        void *dp;
-        unsigned dn = c->d_max ? c->d_max << 1 : 16;
-        while( ns > dn )
-            dn <<= 1;
-
-        dp = realloc( c->data, dn );
-        if( !dp )
-            return -1;
-
-        c->data = dp;
-        c->d_max = dn;
-    }
-
-    memcpy( (char*)c->data + c->d_cur, data, size );
-
-    c->d_cur = ns;
-
-    return 0;
-}
-
-static int mk_write_id( mk_context *c, unsigned id )
-{
-    unsigned char c_id[4] = { id >> 24, id >> 16, id >> 8, id };
-
-    if( c_id[0] )
-        return mk_append_context_data( c, c_id, 4 );
-    if( c_id[1] )
-        return mk_append_context_data( c, c_id+1, 3 );
-    if( c_id[2] )
-        return mk_append_context_data( c, c_id+2, 2 );
-    return mk_append_context_data( c, c_id+3, 1 );
-}
-
-static int mk_write_size( mk_context *c, unsigned size )
-{
-    unsigned char c_size[5] = { 0x08, size >> 24, size >> 16, size >> 8, size };
-
-    if( size < 0x7f )
-    {
-        c_size[4] |= 0x80;
-        return mk_append_context_data( c, c_size+4, 1 );
-    }
-    if( size < 0x3fff )
-    {
-        c_size[3] |= 0x40;
-        return mk_append_context_data( c, c_size+3, 2 );
-    }
-    if( size < 0x1fffff )
-    {
-        c_size[2] |= 0x20;
-        return mk_append_context_data( c, c_size+2, 3 );
-    }
-    if( size < 0x0fffffff )
-    {
-        c_size[1] |= 0x10;
-        return mk_append_context_data( c, c_size+1, 4 );
-    }
-    return mk_append_context_data( c, c_size, 5 );
-}
-
-static int mk_flush_context_id( mk_context *c )
-{
-    unsigned char ff = 0xff;
-
-    if( !c->id )
-        return 0;
-
-    CHECK( mk_write_id( c->parent, c->id ) );
-    CHECK( mk_append_context_data( c->parent, &ff, 1 ) );
-
-    c->id = 0;
-
-    return 0;
-}
-
-static int mk_flush_context_data(mk_context *c)
-{
-    if( !c->d_cur )
-        return 0;
-
-    if( c->parent )
-        CHECK( mk_append_context_data( c->parent, c->data, c->d_cur ) );
-    else if( fwrite( c->data, c->d_cur, 1, c->owner->fp ) != 1 )
-        return -1;
-
-    c->d_cur = 0;
-
-    return 0;
-}
-
-static int mk_close_context(mk_context *c, unsigned *off)
-{
-    if( c->id )
-    {
-        CHECK( mk_write_id( c->parent, c->id ) );
-        CHECK( mk_write_size( c->parent, c->d_cur ) );
-    }
-
-    if( c->parent && off )
-        *off += c->parent->d_cur;
-
-    CHECK( mk_flush_context_data( c ) );
-
-    if( c->next )
-        c->next->prev = c->prev;
-    *(c->prev) = c->next;
-    c->next = c->owner->freelist;
-    c->owner->freelist = c;
-
-    return 0;
-}
-
-static void mk_destroy_contexts( mk_writer *w )
-{
-    mk_context *cur, *next;
-
-    for( cur = w->freelist; cur; cur = next )
-    {
-        next = cur->next;
-        free( cur->data );
-        free( cur );
-    }
-
-    for( cur = w->actlist; cur; cur = next )
-    {
-        next = cur->next;
-        free( cur->data );
-        free( cur );
-    }
-
-    w->freelist = w->actlist = w->root = NULL;
-}
-
-static int mk_write_string( mk_context *c, unsigned id, const char *str )
-{
-    size_t len = strlen( str );
-
-    CHECK( mk_write_id( c, id ) );
-    CHECK( mk_write_size( c, len ) );
-    CHECK( mk_append_context_data( c, str, len ) );
-    return 0;
-}
-
-static int mk_write_bin( mk_context *c, unsigned id, const void *data, unsigned size )
-{
-    CHECK( mk_write_id( c, id ) );
-    CHECK( mk_write_size( c, size ) );
-    CHECK( mk_append_context_data( c, data, size ) ) ;
-    return 0;
-}
-
-static int mk_write_uint( mk_context *c, unsigned id, int64_t ui )
-{
-    unsigned char c_ui[8] = { ui >> 56, ui >> 48, ui >> 40, ui >> 32, ui >> 24, ui >> 16, ui >> 8, ui };
-    unsigned i = 0;
-
-    CHECK( mk_write_id( c, id ) );
-    while( i < 7 && !c_ui[i] )
-        ++i;
-    CHECK( mk_write_size( c, 8 - i ) );
-    CHECK( mk_append_context_data( c, c_ui+i, 8 - i ) );
-    return 0;
-}
-
-static int mk_write_sint( mk_context *c, unsigned id, int64_t si )
-{
-    unsigned char c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
-    unsigned i = 0;
-
-    CHECK( mk_write_id( c, id ) );
-    if( si < 0 )
-        while( i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80 )
-            ++i;
-    else
-        while( i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80 ) )
-            ++i;
-    CHECK( mk_write_size( c, 8 - i ) );
-    CHECK( mk_append_context_data( c, c_si+i, 8 - i ) );
-    return 0;
-}
-
-static int mk_write_float_raw( mk_context *c, float f )
-{
-    union
-    {
-        float f;
-        unsigned u;
-    } u;
-    unsigned char c_f[4];
-
-    u.f = f;
-    c_f[0] = u.u >> 24;
-    c_f[1] = u.u >> 16;
-    c_f[2] = u.u >> 8;
-    c_f[3] = u.u;
-
-    return mk_append_context_data( c, c_f, 4 );
-}
-
-static int mk_write_float( mk_context *c, unsigned id, float f )
-{
-    CHECK( mk_write_id( c, id ) );
-    CHECK( mk_write_size( c, 4 ) );
-    CHECK( mk_write_float_raw( c, f ) );
-    return 0;
-}
-
-static unsigned mk_ebml_size_size( unsigned s )
-{
-    if( s < 0x7f )
-        return 1;
-    if( s < 0x3fff )
-        return 2;
-    if( s < 0x1fffff )
-        return 3;
-    if( s < 0x0fffffff )
-        return 4;
-    return 5;
-}
-
-static unsigned mk_ebml_sint_size( int64_t si )
-{
-    unsigned char c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
-    unsigned i = 0;
-
-    if( si < 0 )
-        while( i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80 )
-            ++i;
-    else
-        while( i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80) )
-            ++i;
-
-    return 8 - i;
-}
-
-mk_writer *mk_create_writer( const char *filename )
-{
-    mk_writer *w = malloc( sizeof(*w) );
-    if( !w )
-        return NULL;
-
-    memset( w, 0, sizeof(*w) );
-
-    w->root = mk_create_context( w, NULL, 0 );
-    if( !w->root )
-    {
-        free( w );
-        return NULL;
-    }
-
-    w->fp = fopen( filename, "wb" );
-    if( !w->fp )
-    {
-        mk_destroy_contexts( w );
-        free( w );
-        return NULL;
-    }
-
-    w->timescale = 1000000;
-
-    return w;
-}
-
-int mk_writeHeader( mk_writer *w, const char *writing_app,
-                    const char *codec_id,
-                    const void *codec_private, unsigned codec_private_size,
-                    int64_t default_frame_duration,
-                    int64_t timescale,
-                    unsigned width, unsigned height,
-                    unsigned d_width, unsigned d_height )
-{
-    mk_context  *c, *ti, *v;
-
-    if( w->wrote_header )
-        return -1;
-
-    w->timescale = timescale;
-    w->def_duration = default_frame_duration;
-
-    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_write_uint( c, 0x42f2, 4 ) ); // EBMLMaxIDLength
-    CHECK( mk_write_uint( c, 0x42f3, 8 ) ); // EBMLMaxSizeLength
-    CHECK( mk_write_string( c, 0x4282, "matroska") ); // DocType
-    CHECK( mk_write_uint( c, 0x4287, 1 ) ); // DocTypeVersion
-    CHECK( mk_write_uint( c, 0x4285, 1 ) ); // DocTypeReadversion
-    CHECK( mk_close_context( c, 0 ) );
-
-    if( !(c = mk_create_context( w, w->root, 0x18538067 )) ) // Segment
-        return -1;
-    CHECK( mk_flush_context_id( c ) );
-    CHECK( mk_close_context( c, 0 ) );
-
-    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_write_uint( c, 0x2ad7b1, w->timescale ) );
-    CHECK( mk_write_float( c, 0x4489, 0) );
-    w->duration_ptr = c->d_cur - 4;
-    CHECK( mk_close_context( c, &w->duration_ptr ) );
-
-    if( !(c = mk_create_context( w, w->root, 0x1654ae6b )) ) // tracks
-        return -1;
-    if( !(ti = mk_create_context( w, c, 0xae )) ) // TrackEntry
-        return -1;
-    CHECK( mk_write_uint( ti, 0xd7, 1 ) ); // TrackNumber
-    CHECK( mk_write_uint( ti, 0x73c5, 1 ) ); // TrackUID
-    CHECK( mk_write_uint( ti, 0x83, 1 ) ); // TrackType
-    CHECK( mk_write_uint( ti, 0x9c, 0 ) ); // FlagLacing
-    CHECK( mk_write_string( ti, 0x86, codec_id ) ); // codec_id
-    if( codec_private_size )
-        CHECK( mk_write_bin( ti, 0x63a2, codec_private, codec_private_size ) ); // codec_private
-    if( default_frame_duration )
-        CHECK( mk_write_uint( ti, 0x23e383, default_frame_duration ) ); // DefaultDuration
-
-    if( !(v = mk_create_context( w, ti, 0xe0 ) ) ) // Video
-        return -1;
-    CHECK( mk_write_uint( v, 0xb0, width ) );
-    CHECK( mk_write_uint( v, 0xba, height ) );
-    CHECK( mk_write_uint( v, 0x54b0, d_width ) );
-    CHECK( mk_write_uint( v, 0x54ba, d_height ) );
-    CHECK( mk_close_context( v, 0 ) );
-
-    CHECK( mk_close_context( ti, 0 ) );
-
-    CHECK( mk_close_context( c, 0 ) );
-
-    CHECK( mk_flush_context_data( w->root ) );
-
-    w->wrote_header = 1;
-
-    return 0;
-}
-
-static int mk_close_cluster( mk_writer *w )
-{
-    if( w->cluster == NULL )
-        return 0;
-    CHECK( mk_close_context( w->cluster, 0 ) );
-    w->cluster = NULL;
-    CHECK( mk_flush_context_data( w->root ) );
-    return 0;
-}
-
-static int mk_flush_frame( mk_writer *w )
-{
-    int64_t delta, ref = 0;
-    unsigned fsize, bgsize;
-    unsigned char c_delta_flags[3];
-
-    if( !w->in_frame )
-        return 0;
-
-    delta = w->frame_tc/w->timescale - w->cluster_tc_scaled;
-    if( delta > 32767ll || delta < -32768ll )
-        CHECK( mk_close_cluster( w ) );
-
-    if( !w->cluster )
-    {
-        w->cluster_tc_scaled = w->frame_tc / w->timescale;
-        w->cluster = mk_create_context( w, w->root, 0x1f43b675 ); // Cluster
-        if( !w->cluster )
-            return -1;
-
-        CHECK( mk_write_uint( w->cluster, 0xe7, w->cluster_tc_scaled ) ); // Timecode
-
-        delta = 0;
-    }
-
-    fsize = w->frame ? w->frame->d_cur : 0;
-    bgsize = fsize + 4 + mk_ebml_size_size( fsize + 4 ) + 1;
-    if( !w->keyframe )
-    {
-        ref = w->prev_frame_tc_scaled - w->cluster_tc_scaled - delta;
-        bgsize += 1 + 1 + mk_ebml_sint_size( ref );
-    }
-
-    CHECK( mk_write_id( w->cluster, 0xa0 ) ); // BlockGroup
-    CHECK( mk_write_size( w->cluster, bgsize ) );
-    CHECK( mk_write_id( w->cluster, 0xa1 ) ); // Block
-    CHECK( mk_write_size( w->cluster, fsize + 4 ) );
-    CHECK( mk_write_size( w->cluster, 1 ) ); // track number
-
-    c_delta_flags[0] = delta >> 8;
-    c_delta_flags[1] = delta;
-    c_delta_flags[2] = 0;
-    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));
-        w->frame->d_cur = 0;
-    }
-    if( !w->keyframe )
-        CHECK( mk_write_sint(w->cluster, 0xfb, ref ) ); // ReferenceBlock
-
-    w->in_frame = 0;
-    w->prev_frame_tc_scaled = w->cluster_tc_scaled + delta;
-
-    if( w->cluster->d_cur > CLSIZE )
-        CHECK( mk_close_cluster( w ) );
-
-    return 0;
-}
-
-int mk_start_frame( mk_writer *w )
-{
-    if( mk_flush_frame( w ) < 0 )
-        return -1;
-
-    w->in_frame = 1;
-    w->keyframe = 0;
-
-    return 0;
-}
-
-int mk_set_frame_flags( mk_writer *w,int64_t timestamp, int keyframe )
-{
-    if( !w->in_frame )
-        return -1;
-
-    w->frame_tc = timestamp;
-    w->keyframe = keyframe != 0;
-
-    if( w->max_frame_tc < timestamp )
-        w->max_frame_tc = timestamp;
-
-    return 0;
-}
-
-int mk_add_frame_data( mk_writer *w, const void *data, unsigned size )
-{
-    if( !w->in_frame )
-        return -1;
-
-    if( !w->frame )
-        if( !(w->frame = mk_create_context( w, NULL, 0 )) )
-        return -1;
-
-  return mk_append_context_data( w->frame, data, size );
-}
-
-int mk_close( mk_writer *w )
-{
-    int ret = 0;
-    if( mk_flush_frame( w ) < 0 || mk_close_cluster( w ) < 0 )
-        ret = -1;
-    if( w->wrote_header )
-    {
-        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 )
-            ret = -1;
-    }
-    mk_destroy_contexts( w );
-    fclose( w->fp );
-    free( w );
-    return ret;
-}
-
diff --git a/matroska.h b/matroska.h
deleted file mode 100644 (file)
index aa6c94c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*****************************************************************************
- * matroska.h:
- *****************************************************************************
- * 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.
- *****************************************************************************/
-
-#ifndef X264_MATROSKA_H
-#define X264_MATROSKA_H
-
-typedef struct mk_writer mk_writer;
-
-mk_writer *mk_create_writer( const char *filename );
-
-int mk_writeHeader( mk_writer *w, const char *writing_app,
-                    const char *codec_id,
-                    const void *codec_private, unsigned codec_private_size,
-                    int64_t default_frame_duration,
-                    int64_t timescale,
-                    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 );
-
-#endif
diff --git a/muxers.c b/muxers.c
deleted file mode 100644 (file)
index 1a8187d..0000000
--- a/muxers.c
+++ /dev/null
@@ -1,1048 +0,0 @@
-/*****************************************************************************
- * 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;
-}
-
index aaede1c..44ea966 100644 (file)
--- a/muxers.h
+++ b/muxers.h
@@ -1,7 +1,7 @@
 /*****************************************************************************
- * 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
diff --git a/output/matroska.c b/output/matroska.c
new file mode 100644 (file)
index 0000000..e986a75
--- /dev/null
@@ -0,0 +1,245 @@
+/*****************************************************************************
+ * 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 };
diff --git a/output/matroska_ebml.c b/output/matroska_ebml.c
new file mode 100644 (file)
index 0000000..4e6bf0c
--- /dev/null
@@ -0,0 +1,559 @@
+/*****************************************************************************
+ * matroska_ebml.c:
+ *****************************************************************************
+ * 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 <stdlib.h>
+#include <string.h>
+#include "common/osdep.h"
+#include "matroska_ebml.h"
+
+#define CLSIZE 1048576
+#define CHECK(x)\
+do {\
+    if( (x) < 0 )\
+        return -1;\
+} while( 0 )
+
+struct mk_context
+{
+    struct mk_context *next, **prev, *parent;
+    mk_writer *owner;
+    unsigned id;
+
+    void *data;
+    unsigned d_cur, d_max;
+};
+
+typedef struct mk_context mk_context;
+
+struct mk_writer
+{
+    FILE *fp;
+
+    unsigned duration_ptr;
+
+    mk_context *root, *cluster, *frame;
+    mk_context *freelist;
+    mk_context *actlist;
+
+    int64_t def_duration;
+    int64_t timescale;
+    int64_t cluster_tc_scaled;
+    int64_t frame_tc, prev_frame_tc_scaled, max_frame_tc;
+
+    char wrote_header, in_frame, keyframe;
+};
+
+static mk_context *mk_create_context( mk_writer *w, mk_context *parent, unsigned id )
+{
+    mk_context *c;
+
+    if( w->freelist )
+    {
+        c = w->freelist;
+        w->freelist = w->freelist->next;
+    }
+    else
+    {
+        c = malloc( sizeof(*c) );
+        if( !c )
+            return NULL;
+        memset( c, 0, sizeof(*c) );
+    }
+
+    c->parent = parent;
+    c->owner = w;
+    c->id = id;
+
+    if( c->owner->actlist )
+        c->owner->actlist->prev = &c->next;
+    c->next = c->owner->actlist;
+    c->prev = &c->owner->actlist;
+    c->owner->actlist = c;
+
+    return c;
+}
+
+static int mk_append_context_data( mk_context *c, const void *data, unsigned size )
+{
+    unsigned ns = c->d_cur + size;
+
+    if( ns > c->d_max )
+    {
+        void *dp;
+        unsigned dn = c->d_max ? c->d_max << 1 : 16;
+        while( ns > dn )
+            dn <<= 1;
+
+        dp = realloc( c->data, dn );
+        if( !dp )
+            return -1;
+
+        c->data = dp;
+        c->d_max = dn;
+    }
+
+    memcpy( (char*)c->data + c->d_cur, data, size );
+
+    c->d_cur = ns;
+
+    return 0;
+}
+
+static int mk_write_id( mk_context *c, unsigned id )
+{
+    unsigned char c_id[4] = { id >> 24, id >> 16, id >> 8, id };
+
+    if( c_id[0] )
+        return mk_append_context_data( c, c_id, 4 );
+    if( c_id[1] )
+        return mk_append_context_data( c, c_id+1, 3 );
+    if( c_id[2] )
+        return mk_append_context_data( c, c_id+2, 2 );
+    return mk_append_context_data( c, c_id+3, 1 );
+}
+
+static int mk_write_size( mk_context *c, unsigned size )
+{
+    unsigned char c_size[5] = { 0x08, size >> 24, size >> 16, size >> 8, size };
+
+    if( size < 0x7f )
+    {
+        c_size[4] |= 0x80;
+        return mk_append_context_data( c, c_size+4, 1 );
+    }
+    if( size < 0x3fff )
+    {
+        c_size[3] |= 0x40;
+        return mk_append_context_data( c, c_size+3, 2 );
+    }
+    if( size < 0x1fffff )
+    {
+        c_size[2] |= 0x20;
+        return mk_append_context_data( c, c_size+2, 3 );
+    }
+    if( size < 0x0fffffff )
+    {
+        c_size[1] |= 0x10;
+        return mk_append_context_data( c, c_size+1, 4 );
+    }
+    return mk_append_context_data( c, c_size, 5 );
+}
+
+static int mk_flush_context_id( mk_context *c )
+{
+    unsigned char ff = 0xff;
+
+    if( !c->id )
+        return 0;
+
+    CHECK( mk_write_id( c->parent, c->id ) );
+    CHECK( mk_append_context_data( c->parent, &ff, 1 ) );
+
+    c->id = 0;
+
+    return 0;
+}
+
+static int mk_flush_context_data( mk_context *c )
+{
+    if( !c->d_cur )
+        return 0;
+
+    if( c->parent )
+        CHECK( mk_append_context_data( c->parent, c->data, c->d_cur ) );
+    else if( fwrite( c->data, c->d_cur, 1, c->owner->fp ) != 1 )
+        return -1;
+
+    c->d_cur = 0;
+
+    return 0;
+}
+
+static int mk_close_context( mk_context *c, unsigned *off )
+{
+    if( c->id )
+    {
+        CHECK( mk_write_id( c->parent, c->id ) );
+        CHECK( mk_write_size( c->parent, c->d_cur ) );
+    }
+
+    if( c->parent && off )
+        *off += c->parent->d_cur;
+
+    CHECK( mk_flush_context_data( c ) );
+
+    if( c->next )
+        c->next->prev = c->prev;
+    *(c->prev) = c->next;
+    c->next = c->owner->freelist;
+    c->owner->freelist = c;
+
+    return 0;
+}
+
+static void mk_destroy_contexts( mk_writer *w )
+{
+    mk_context *cur, *next;
+
+    for( cur = w->freelist; cur; cur = next )
+    {
+        next = cur->next;
+        free( cur->data );
+        free( cur );
+    }
+
+    for( cur = w->actlist; cur; cur = next )
+    {
+        next = cur->next;
+        free( cur->data );
+        free( cur );
+    }
+
+    w->freelist = w->actlist = w->root = NULL;
+}
+
+static int mk_write_string( mk_context *c, unsigned id, const char *str )
+{
+    size_t len = strlen( str );
+
+    CHECK( mk_write_id( c, id ) );
+    CHECK( mk_write_size( c, len ) );
+    CHECK( mk_append_context_data( c, str, len ) );
+    return 0;
+}
+
+static int mk_write_bin( mk_context *c, unsigned id, const void *data, unsigned size )
+{
+    CHECK( mk_write_id( c, id ) );
+    CHECK( mk_write_size( c, size ) );
+    CHECK( mk_append_context_data( c, data, size ) ) ;
+    return 0;
+}
+
+static int mk_write_uint( mk_context *c, unsigned id, int64_t ui )
+{
+    unsigned char c_ui[8] = { ui >> 56, ui >> 48, ui >> 40, ui >> 32, ui >> 24, ui >> 16, ui >> 8, ui };
+    unsigned i = 0;
+
+    CHECK( mk_write_id( c, id ) );
+    while( i < 7 && !c_ui[i] )
+        ++i;
+    CHECK( mk_write_size( c, 8 - i ) );
+    CHECK( mk_append_context_data( c, c_ui+i, 8 - i ) );
+    return 0;
+}
+
+static int mk_write_sint( mk_context *c, unsigned id, int64_t si )
+{
+    unsigned char c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
+    unsigned i = 0;
+
+    CHECK( mk_write_id( c, id ) );
+    if( si < 0 )
+        while( i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80 )
+            ++i;
+    else
+        while( i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80 ) )
+            ++i;
+    CHECK( mk_write_size( c, 8 - i ) );
+    CHECK( mk_append_context_data( c, c_si+i, 8 - i ) );
+    return 0;
+}
+
+static int mk_write_float_raw( mk_context *c, float f )
+{
+    union
+    {
+        float f;
+        unsigned u;
+    } u;
+    unsigned char c_f[4];
+
+    u.f = f;
+    c_f[0] = u.u >> 24;
+    c_f[1] = u.u >> 16;
+    c_f[2] = u.u >> 8;
+    c_f[3] = u.u;
+
+    return mk_append_context_data( c, c_f, 4 );
+}
+
+static int mk_write_float( mk_context *c, unsigned id, float f )
+{
+    CHECK( mk_write_id( c, id ) );
+    CHECK( mk_write_size( c, 4 ) );
+    CHECK( mk_write_float_raw( c, f ) );
+    return 0;
+}
+
+static unsigned mk_ebml_size_size( unsigned s )
+{
+    if( s < 0x7f )
+        return 1;
+    if( s < 0x3fff )
+        return 2;
+    if( s < 0x1fffff )
+        return 3;
+    if( s < 0x0fffffff )
+        return 4;
+    return 5;
+}
+
+static unsigned mk_ebml_sint_size( int64_t si )
+{
+    unsigned char c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
+    unsigned i = 0;
+
+    if( si < 0 )
+        while( i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80 )
+            ++i;
+    else
+        while( i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80) )
+            ++i;
+
+    return 8 - i;
+}
+
+mk_writer *mk_create_writer( const char *filename )
+{
+    mk_writer *w = malloc( sizeof(*w) );
+    if( !w )
+        return NULL;
+
+    memset( w, 0, sizeof(*w) );
+
+    w->root = mk_create_context( w, NULL, 0 );
+    if( !w->root )
+    {
+        free( w );
+        return NULL;
+    }
+
+    w->fp = fopen( filename, "wb" );
+    if( !w->fp )
+    {
+        mk_destroy_contexts( w );
+        free( w );
+        return NULL;
+    }
+
+    w->timescale = 1000000;
+
+    return w;
+}
+
+int mk_writeHeader( mk_writer *w, const char *writing_app,
+                    const char *codec_id,
+                    const void *codec_private, unsigned codec_private_size,
+                    int64_t default_frame_duration,
+                    int64_t timescale,
+                    unsigned width, unsigned height,
+                    unsigned d_width, unsigned d_height )
+{
+    mk_context  *c, *ti, *v;
+
+    if( w->wrote_header )
+        return -1;
+
+    w->timescale = timescale;
+    w->def_duration = default_frame_duration;
+
+    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_write_uint( c, 0x42f2, 4 ) ); // EBMLMaxIDLength
+    CHECK( mk_write_uint( c, 0x42f3, 8 ) ); // EBMLMaxSizeLength
+    CHECK( mk_write_string( c, 0x4282, "matroska") ); // DocType
+    CHECK( mk_write_uint( c, 0x4287, 1 ) ); // DocTypeVersion
+    CHECK( mk_write_uint( c, 0x4285, 1 ) ); // DocTypeReadversion
+    CHECK( mk_close_context( c, 0 ) );
+
+    if( !(c = mk_create_context( w, w->root, 0x18538067 )) ) // Segment
+        return -1;
+    CHECK( mk_flush_context_id( c ) );
+    CHECK( mk_close_context( c, 0 ) );
+
+    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_write_uint( c, 0x2ad7b1, w->timescale ) );
+    CHECK( mk_write_float( c, 0x4489, 0) );
+    w->duration_ptr = c->d_cur - 4;
+    CHECK( mk_close_context( c, &w->duration_ptr ) );
+
+    if( !(c = mk_create_context( w, w->root, 0x1654ae6b )) ) // tracks
+        return -1;
+    if( !(ti = mk_create_context( w, c, 0xae )) ) // TrackEntry
+        return -1;
+    CHECK( mk_write_uint( ti, 0xd7, 1 ) ); // TrackNumber
+    CHECK( mk_write_uint( ti, 0x73c5, 1 ) ); // TrackUID
+    CHECK( mk_write_uint( ti, 0x83, 1 ) ); // TrackType
+    CHECK( mk_write_uint( ti, 0x9c, 0 ) ); // FlagLacing
+    CHECK( mk_write_string( ti, 0x86, codec_id ) ); // codec_id
+    if( codec_private_size )
+        CHECK( mk_write_bin( ti, 0x63a2, codec_private, codec_private_size ) ); // codec_private
+    if( default_frame_duration )
+        CHECK( mk_write_uint( ti, 0x23e383, default_frame_duration ) ); // DefaultDuration
+
+    if( !(v = mk_create_context( w, ti, 0xe0 ) ) ) // Video
+        return -1;
+    CHECK( mk_write_uint( v, 0xb0, width ) );
+    CHECK( mk_write_uint( v, 0xba, height ) );
+    CHECK( mk_write_uint( v, 0x54b0, d_width ) );
+    CHECK( mk_write_uint( v, 0x54ba, d_height ) );
+    CHECK( mk_close_context( v, 0 ) );
+
+    CHECK( mk_close_context( ti, 0 ) );
+
+    CHECK( mk_close_context( c, 0 ) );
+
+    CHECK( mk_flush_context_data( w->root ) );
+
+    w->wrote_header = 1;
+
+    return 0;
+}
+
+static int mk_close_cluster( mk_writer *w )
+{
+    if( w->cluster == NULL )
+        return 0;
+    CHECK( mk_close_context( w->cluster, 0 ) );
+    w->cluster = NULL;
+    CHECK( mk_flush_context_data( w->root ) );
+    return 0;
+}
+
+static int mk_flush_frame( mk_writer *w )
+{
+    int64_t delta, ref = 0;
+    unsigned fsize, bgsize;
+    unsigned char c_delta_flags[3];
+
+    if( !w->in_frame )
+        return 0;
+
+    delta = w->frame_tc/w->timescale - w->cluster_tc_scaled;
+    if( delta > 32767ll || delta < -32768ll )
+        CHECK( mk_close_cluster( w ) );
+
+    if( !w->cluster )
+    {
+        w->cluster_tc_scaled = w->frame_tc / w->timescale;
+        w->cluster = mk_create_context( w, w->root, 0x1f43b675 ); // Cluster
+        if( !w->cluster )
+            return -1;
+
+        CHECK( mk_write_uint( w->cluster, 0xe7, w->cluster_tc_scaled ) ); // Timecode
+
+        delta = 0;
+    }
+
+    fsize = w->frame ? w->frame->d_cur : 0;
+    bgsize = fsize + 4 + mk_ebml_size_size( fsize + 4 ) + 1;
+    if( !w->keyframe )
+    {
+        ref = w->prev_frame_tc_scaled - w->cluster_tc_scaled - delta;
+        bgsize += 1 + 1 + mk_ebml_sint_size( ref );
+    }
+
+    CHECK( mk_write_id( w->cluster, 0xa0 ) ); // BlockGroup
+    CHECK( mk_write_size( w->cluster, bgsize ) );
+    CHECK( mk_write_id( w->cluster, 0xa1 ) ); // Block
+    CHECK( mk_write_size( w->cluster, fsize + 4 ) );
+    CHECK( mk_write_size( w->cluster, 1 ) ); // track number
+
+    c_delta_flags[0] = delta >> 8;
+    c_delta_flags[1] = delta;
+    c_delta_flags[2] = 0;
+    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 ) );
+        w->frame->d_cur = 0;
+    }
+    if( !w->keyframe )
+        CHECK( mk_write_sint( w->cluster, 0xfb, ref ) ); // ReferenceBlock
+
+    w->in_frame = 0;
+    w->prev_frame_tc_scaled = w->cluster_tc_scaled + delta;
+
+    if( w->cluster->d_cur > CLSIZE )
+        CHECK( mk_close_cluster( w ) );
+
+    return 0;
+}
+
+int mk_start_frame( mk_writer *w )
+{
+    if( mk_flush_frame( w ) < 0 )
+        return -1;
+
+    w->in_frame = 1;
+    w->keyframe = 0;
+
+    return 0;
+}
+
+int mk_set_frame_flags( mk_writer *w, int64_t timestamp, int keyframe )
+{
+    if( !w->in_frame )
+        return -1;
+
+    w->frame_tc = timestamp;
+    w->keyframe = keyframe != 0;
+
+    if( w->max_frame_tc < timestamp )
+        w->max_frame_tc = timestamp;
+
+    return 0;
+}
+
+int mk_add_frame_data( mk_writer *w, const void *data, unsigned size )
+{
+    if( !w->in_frame )
+        return -1;
+
+    if( !w->frame )
+        if( !(w->frame = mk_create_context( w, NULL, 0 )) )
+        return -1;
+
+    return mk_append_context_data( w->frame, data, size );
+}
+
+int mk_close( mk_writer *w )
+{
+    int ret = 0;
+    if( mk_flush_frame( w ) < 0 || mk_close_cluster( w ) < 0 )
+        ret = -1;
+    if( w->wrote_header )
+    {
+        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 )
+            ret = -1;
+    }
+    mk_destroy_contexts( w );
+    fclose( w->fp );
+    free( w );
+    return ret;
+}
diff --git a/output/matroska_ebml.h b/output/matroska_ebml.h
new file mode 100644 (file)
index 0000000..f8c641b
--- /dev/null
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ * matroska_ebml.h:
+ *****************************************************************************
+ * 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.
+ *****************************************************************************/
+
+#ifndef X264_MATROSKA_EBML_H
+#define X264_MATROSKA_EBML_H
+
+typedef struct mk_writer mk_writer;
+
+mk_writer *mk_create_writer( const char *filename );
+
+int mk_writeHeader( mk_writer *w, const char *writing_app,
+                    const char *codec_id,
+                    const void *codec_private, unsigned codec_private_size,
+                    int64_t default_frame_duration,
+                    int64_t timescale,
+                    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 );
+
+#endif
diff --git a/output/mp4.c b/output/mp4.c
new file mode 100644 (file)
index 0000000..c361b2b
--- /dev/null
@@ -0,0 +1,277 @@
+/*****************************************************************************
+ * 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 };
diff --git a/output/output.h b/output/output.h
new file mode 100644 (file)
index 0000000..5409f15
--- /dev/null
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * 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
diff --git a/output/raw.c b/output/raw.c
new file mode 100644 (file)
index 0000000..bc0b0da
--- /dev/null
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ * 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 };
diff --git a/x264.c b/x264.c
index fc4e44f..4ffa785 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -61,18 +61,9 @@ typedef struct {
     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 );
@@ -550,18 +541,9 @@ static int  Parse( int argc, char **argv,
     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;; )
@@ -795,27 +777,17 @@ static int  Parse( int argc, char **argv,
                 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;
@@ -1001,24 +973,16 @@ generic_option:
         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;
@@ -1035,18 +999,13 @@ generic_option:
     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
 
@@ -1129,13 +1088,13 @@ static int  Encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic )
 
     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;
 }
@@ -1174,7 +1133,7 @@ static int  Encode( x264_param_t *param, cli_opt_t *opt )
     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 )
@@ -1185,15 +1144,15 @@ static int  Encode( x264_param_t *param, cli_opt_t *opt )
     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;
     }
 
@@ -1209,7 +1168,7 @@ static int  Encode( x264_param_t *param, cli_opt_t *opt )
     /* 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;
@@ -1261,8 +1220,8 @@ static int  Encode( x264_param_t *param, cli_opt_t *opt )
     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 )
     {