encoder/cavlc.c encoder/encoder.c encoder/lookahead.c
SRCCLI = x264.c input/yuv.c input/y4m.c output/raw.c \
- output/matroska.c output/matroska_ebml.c
+ output/matroska.c output/matroska_ebml.c \
+ output/flv.c output/flv_bytestream.c
MUXERS := $(shell grep -E "(IN|OUT)PUT" config.h)
#ifdef WORDS_BIGENDIAN
#define endian_fix(x) (x)
+#define endian_fix64(x) (x)
#define endian_fix32(x) (x)
#define endian_fix16(x) (x)
#else
asm("bswap %0":"+r"(x));
return x;
}
-static ALWAYS_INLINE intptr_t endian_fix( intptr_t x )
-{
- asm("bswap %0":"+r"(x));
- return x;
-}
#elif defined(__GNUC__) && defined(HAVE_ARMV6)
-static ALWAYS_INLINE intptr_t endian_fix( intptr_t x )
+static ALWAYS_INLINE uint32_t endian_fix32( uint32_t x )
{
asm("rev %0, %0":"+r"(x));
return x;
}
-#define endian_fix32 endian_fix
#else
static ALWAYS_INLINE uint32_t endian_fix32( uint32_t x )
{
return (x<<24) + ((x<<8)&0xff0000) + ((x>>8)&0xff00) + (x>>24);
}
-static ALWAYS_INLINE intptr_t endian_fix( intptr_t x )
+#endif
+#if defined(__GNUC__) && defined(ARCH_X86_64)
+static ALWAYS_INLINE uint64_t endian_fix64( uint64_t x )
{
- if( WORD_SIZE == 8 )
- return endian_fix32(x>>32) + ((uint64_t)endian_fix32(x)<<32);
- else
- return endian_fix32(x);
+ asm("bswap %0":"+r"(x));
+ return x;
+}
+#else
+static ALWAYS_INLINE uint64_t endian_fix64( uint64_t x )
+{
+ return endian_fix32(x>>32) + ((uint64_t)endian_fix32(x)<<32);
}
#endif
+static ALWAYS_INLINE intptr_t endian_fix( intptr_t x )
+{
+ return WORD_SIZE == 8 ? endian_fix64(x) : endian_fix32(x);
+}
static ALWAYS_INLINE uint16_t endian_fix16( uint16_t x )
{
return (x<<8)|(x>>8);
CFLAGS="$CFLAGS -DARCH_$ARCH -DSYS_$SYS"
-echo "unsigned int endian = 'B' << 24 | 'I' << 16 | 'G' << 8 | 'E';" > conftest.c
+echo "int i = 0x42494745; double f = 0x1.0656e6469616ep+102;" > conftest.c
$CC $CFLAGS conftest.c -c -o conftest.o 2>$DEVNULL || die "endian test failed"
-grep -q BIGE conftest.o && CFLAGS="$CFLAGS -DWORDS_BIGENDIAN"
+if grep -q BIGE conftest.o && grep -q FPendian conftest.o ; then
+ CFLAGS="$CFLAGS -DWORDS_BIGENDIAN"
+elif !(grep -q EGIB conftest.o && grep -q naidnePF conftest.o) ; then
+ die "endian test failed"
+fi
# autodetect options that weren't forced nor disabled
--- /dev/null
+/*****************************************************************************
+ * flv.c:
+ *****************************************************************************
+ * Copyright (C) 2009 Kieran Kunhya
+ *
+ * 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 "flv_bytestream.h"
+#define CHECK(x)\
+do {\
+ if( (x) < 0 )\
+ return -1;\
+} while( 0 )
+
+typedef struct
+{
+ flv_buffer *c;
+
+ uint8_t b_sps;
+ uint8_t b_pps;
+ uint8_t *sei;
+ int sei_len;
+
+ int64_t i_fps_num;
+ int64_t i_fps_den;
+ int64_t i_init_delay;
+ int64_t i_framenum;
+ int64_t i_mspf;
+
+ uint64_t i_duration_pos;
+ uint64_t i_filesize_pos;
+ uint64_t i_bitrate_pos;
+
+ uint8_t b_write_length;
+
+ unsigned start;
+} flv_hnd_t;
+
+static int write_header( flv_buffer *c )
+{
+ put_tag( c, "FLV" ); // Signature
+ put_byte( c, 1 ); // Version
+ put_byte( c, 1 ); // Video Only
+ put_be32( c, 9 ); // DataOffset
+ put_be32( c, 0 ); // PreviousTagSize0
+
+ return flv_flush_data( c );
+}
+
+static int open_file( char *psz_filename, hnd_t *p_handle )
+{
+ flv_hnd_t *p_flv = malloc( sizeof(*p_flv) );
+ *p_handle = NULL;
+ if( !p_flv )
+ return -1;
+ memset( p_flv, 0, sizeof(*p_flv) );
+
+ p_flv->c = flv_create_writer( psz_filename );
+ if( !p_flv->c )
+ return -1;
+
+ CHECK( write_header( p_flv->c ) );
+ *p_handle = p_flv;
+
+ return 0;
+}
+
+static int set_param( hnd_t handle, x264_param_t *p_param )
+{
+ flv_hnd_t *p_flv = handle;
+ flv_buffer *c = p_flv->c;
+
+ put_byte( c, FLV_TAG_TYPE_META ); // Tag Type "script data"
+
+ int start = c->d_cur;
+ put_be24( c, 0 ); // data length
+ put_be24( c, 0 ); // timestamp
+ put_be32( c, 0 ); // reserved
+
+ put_byte( c, AMF_DATA_TYPE_STRING );
+ put_amf_string( c, "onMetaData" );
+
+ put_byte( c, AMF_DATA_TYPE_MIXEDARRAY );
+ put_be32( c, 7 );
+
+ put_amf_string( c, "width" );
+ put_amf_double( c, p_param->i_width );
+
+ put_amf_string( c, "height" );
+ put_amf_double( c, p_param->i_height );
+
+ put_amf_string( c, "framerate" );
+ put_amf_double( c, p_param->i_fps_num / p_param->i_fps_den );
+
+ put_amf_string( c, "videocodecid" );
+ put_amf_double( c, FLV_CODECID_H264 );
+
+ put_amf_string( c, "duration" );
+ p_flv->i_duration_pos = c->d_cur + c->d_total + 1; // + 1 because of the following AMF_DATA_TYPE_NUMBER byte
+ put_amf_double( c, 0 ); // written at end of encoding
+
+ put_amf_string( c, "filesize" );
+ p_flv->i_filesize_pos = c->d_cur + c->d_total + 1;
+ put_amf_double( c, 0 ); // written at end of encoding
+
+ put_amf_string( c, "videodatarate" );
+ p_flv->i_bitrate_pos = c->d_cur + c->d_total + 1;
+ put_amf_double( c, 0 ); // written at end of encoding
+
+ put_amf_string( c, "" );
+ put_byte( c, AMF_END_OF_OBJECT );
+
+ unsigned length = c->d_cur - start;
+ rewrite_amf_be24( c, length - 10, start );
+
+ put_be32( c, length + 1 ); // tag length
+
+ p_flv->i_fps_num = p_param->i_fps_num;
+ p_flv->i_fps_den = p_param->i_fps_den;
+ p_flv->i_init_delay = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0;
+ p_flv->i_mspf = 1000 * p_flv->i_fps_den / p_flv->i_fps_num;
+
+ fprintf( stderr, "flv [info]: initial delay %i frames\n",
+ (int)p_flv->i_init_delay );
+
+ return 0;
+}
+
+static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture )
+{
+ flv_hnd_t *p_flv = handle;
+ flv_buffer *c = p_flv->c;
+ uint64_t dts = (uint64_t)p_flv->i_framenum * p_flv->i_mspf;
+ uint64_t pts = (uint64_t)p_picture->i_pts * p_flv->i_mspf / p_flv->i_fps_den;
+ uint64_t timestamp = dts + p_flv->i_init_delay * p_flv->i_mspf;
+ uint64_t offset = p_flv->i_init_delay * p_flv->i_mspf + pts - dts;
+ uint8_t type = p_nalu[4] & 0x1f;
+
+ switch( type )
+ {
+ // sps
+ case 0x07:
+ if( !p_flv->b_sps )
+ {
+ uint8_t *sps = p_nalu + 4;
+
+ put_byte( c, FLV_TAG_TYPE_VIDEO );
+ put_be24( c, 0 ); // rewrite later, pps size unknown
+ put_be24( c, 0 ); // timestamp
+ put_byte( c, 0 ); // timestamp extended
+ put_be24( c, 0 ); // StreamID - Always 0
+ p_flv->start = c->d_cur; // needed for overwriting length
+
+ put_byte( c, 7 | FLV_FRAME_KEY ); // Frametype and CodecID
+ put_byte( c, 0 ); // AVC sequence header
+ put_be24( c, 0 ); // composition time
+
+ put_byte( c, 1 ); // version
+ put_byte( c, sps[1] ); // profile
+ put_byte( c, sps[2] ); // profile
+ put_byte( c, sps[3] ); // level
+ put_byte( c, 0xff ); // 6 bits reserved (111111) + 2 bits nal size length - 1 (11)
+ put_byte( c, 0xe1 ); // 3 bits reserved (111) + 5 bits number of sps (00001)
+
+ put_be16( c, i_size - 4 );
+ flv_append_data( c, sps, i_size - 4 );
+
+ p_flv->b_sps = 1;
+ }
+ break;
+
+ // pps
+ case 0x08:
+ if( !p_flv->b_pps )
+ {
+ put_byte( c, 1 ); // number of pps
+ put_be16( c, i_size - 4 );
+ flv_append_data( c, p_nalu + 4, i_size - 4 );
+
+ // rewrite data length info
+ unsigned length = c->d_cur - p_flv->start;
+ rewrite_amf_be24( c, length, p_flv->start - 10 );
+ put_be32( c, length + 11 ); // Last tag size
+
+ p_flv->b_pps = 1;
+ }
+ break;
+
+ // slice
+ case 0x1:
+ case 0x5:
+ if( !p_flv->b_write_length )
+ {
+ // A new frame - write packet header
+ put_byte( c, FLV_TAG_TYPE_VIDEO );
+ put_be24( c, 0 ); // calculated later
+ put_be24( c, timestamp );
+ put_byte( c, timestamp >> 24 );
+ put_be24( c, 0 );
+
+ p_flv->start = c->d_cur;
+ put_byte( c, p_picture->i_type == X264_TYPE_IDR ? FLV_FRAME_KEY : FLV_FRAME_INTER );
+ put_byte( c, 1 ); // AVC NALU
+ put_be24( c, offset );
+
+ p_flv->b_write_length = 1;
+ }
+ if( p_flv->sei )
+ {
+ flv_append_data( c, p_flv->sei, p_flv->sei_len );
+ free( p_flv->sei );
+ p_flv->sei = NULL;
+ }
+ flv_append_data( c, p_nalu, i_size );
+ break;
+ // sei
+ case 0x6:
+ /* It is within the spec to write this as-is but for
+ * mplayer/ffmpeg playback this is deferred until before the first frame */
+
+ p_flv->sei = malloc( i_size );
+ if( !p_flv->sei )
+ return -1;
+ p_flv->sei_len = i_size;
+
+ memcpy( p_flv->sei, p_nalu, i_size );
+ break;
+ }
+ return i_size;
+}
+
+static int set_eop( hnd_t handle, x264_picture_t *p_picture )
+{
+ flv_hnd_t *p_flv = handle;
+ flv_buffer *c = p_flv->c;
+
+ if( p_flv->b_write_length )
+ {
+ unsigned length = c->d_cur - p_flv->start;
+ rewrite_amf_be24( c, length, p_flv->start - 10 );
+ put_be32( c, 11 + length ); // Last tag size
+ CHECK( flv_flush_data( c ) );
+ p_flv->b_write_length = 0;
+ }
+ p_flv->i_framenum++;
+
+ return 0;
+}
+
+static void rewrite_amf_double( FILE *fp, uint64_t position, double value )
+{
+ uint64_t x = endian_fix64( dbl2int( value ) );
+ fseek( fp, position, SEEK_SET );
+ fwrite( &x, 8, 1, fp );
+}
+
+static int close_file( hnd_t handle )
+{
+ flv_hnd_t *p_flv = handle;
+ flv_buffer *c = p_flv->c;
+
+ CHECK( flv_flush_data( c ) );
+
+ if( x264_is_regular_file( c->fp ) )
+ {
+ double duration = p_flv->i_fps_den * p_flv->i_framenum / p_flv->i_fps_num;
+ uint64_t filesize = ftell( c->fp );
+ rewrite_amf_double( c->fp, p_flv->i_duration_pos, duration );
+ rewrite_amf_double( c->fp, p_flv->i_filesize_pos, filesize );
+ rewrite_amf_double( c->fp, p_flv->i_bitrate_pos, filesize * 8 / ( duration * 1000 ) );
+ }
+
+ fclose( c->fp );
+ free( p_flv );
+ free( c );
+
+ return 0;
+}
+
+cli_output_t flv_output = { open_file, set_param, write_nalu, set_eop, close_file };
--- /dev/null
+/*****************************************************************************
+ * flv_bytestream.c:
+ *****************************************************************************
+ * Copyright (C) 2009 Kieran Kunhya
+ *
+ * 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 <math.h>
+#include "common/common.h"
+#include "flv_bytestream.h"
+
+uint64_t dbl2int( double value )
+{
+ return (union {double f; uint64_t i;}){value}.i;
+}
+
+/* Put functions */
+
+void put_byte( flv_buffer *c, uint8_t b )
+{
+ flv_append_data( c, &b, 1 );
+}
+
+void put_be32( flv_buffer *c, uint32_t val )
+{
+ put_byte( c, val >> 24 );
+ put_byte( c, val >> 16 );
+ put_byte( c, val >> 8 );
+ put_byte( c, val );
+}
+
+void put_be64( flv_buffer *c, uint64_t val )
+{
+ put_be32( c, val >> 32 );
+ put_be32( c, val );
+}
+
+void put_be16( flv_buffer *c, uint16_t val )
+{
+ put_byte( c, val >> 8 );
+ put_byte( c, val );
+}
+
+void put_be24( flv_buffer *c, uint32_t val )
+{
+ put_be16( c, val >> 8 );
+ put_byte( c, val );
+}
+
+void put_tag( flv_buffer *c, const char *tag )
+{
+ while( *tag )
+ put_byte( c, *tag++ );
+}
+
+void put_amf_string( flv_buffer *c, const char *str )
+{
+ uint16_t len = strlen( str );
+ put_be16( c, len );
+ flv_append_data( c, (uint8_t*)str, len );
+}
+
+void put_amf_double( flv_buffer *c, double d )
+{
+ put_byte( c, AMF_DATA_TYPE_NUMBER );
+ put_be64( c, dbl2int( d ) );
+}
+
+/* flv writing functions */
+
+flv_buffer *flv_create_writer( const char *filename )
+{
+ flv_buffer *c = malloc( sizeof(*c) );
+
+ if( !c )
+ return NULL;
+ memset( c, 0, sizeof(*c) );
+
+ if( !strcmp( filename, "-" ) )
+ c->fp = stdout;
+ else
+ c->fp = fopen( filename, "wb" );
+ if( !c->fp )
+ {
+ free( c );
+ return NULL;
+ }
+
+ return c;
+}
+
+int flv_append_data( flv_buffer *c, uint8_t *data, unsigned size )
+{
+ unsigned ns = c->d_cur + size;
+
+ if( ns > c->d_max )
+ {
+ void *dp;
+ unsigned dn = 16;
+ while( ns > dn )
+ dn <<= 1;
+
+ dp = realloc( c->data, dn );
+ if( !dp )
+ return -1;
+
+ c->data = dp;
+ c->d_max = dn;
+ }
+
+ memcpy( c->data + c->d_cur, data, size );
+
+ c->d_cur = ns;
+
+ return 0;
+}
+
+void rewrite_amf_be24( flv_buffer *c, unsigned length, unsigned start )
+{
+ *(c->data + start + 0) = length >> 16;
+ *(c->data + start + 1) = length >> 8;
+ *(c->data + start + 2) = length >> 0;
+}
+
+int flv_flush_data( flv_buffer *c )
+{
+ if( !c->d_cur )
+ return 0;
+
+ if( fwrite( c->data, c->d_cur, 1, c->fp ) != 1 )
+ return -1;
+
+ c->d_total += c->d_cur;
+
+ c->d_cur = 0;
+
+ return 0;
+}
--- /dev/null
+/*****************************************************************************
+ * flv_bytestream.h:
+ *****************************************************************************
+ * Copyright (C) 2009 Kieran Kunhya
+ *
+ * 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_FLV_BYTESTREAM_H
+#define X264_FLV_BYTESTREAM_H
+
+/* offsets for packed values */
+#define FLV_AUDIO_SAMPLESSIZE_OFFSET 1
+#define FLV_AUDIO_SAMPLERATE_OFFSET 2
+#define FLV_AUDIO_CODECID_OFFSET 4
+
+#define FLV_VIDEO_FRAMETYPE_OFFSET 4
+
+/* bitmasks to isolate specific values */
+#define FLV_AUDIO_CHANNEL_MASK 0x01
+#define FLV_AUDIO_SAMPLESIZE_MASK 0x02
+#define FLV_AUDIO_SAMPLERATE_MASK 0x0c
+#define FLV_AUDIO_CODECID_MASK 0xf0
+
+#define FLV_VIDEO_CODECID_MASK 0x0f
+#define FLV_VIDEO_FRAMETYPE_MASK 0xf0
+
+#define AMF_END_OF_OBJECT 0x09
+
+enum
+{
+ FLV_HEADER_FLAG_HASVIDEO = 1,
+ FLV_HEADER_FLAG_HASAUDIO = 4,
+};
+
+enum
+{
+ FLV_TAG_TYPE_AUDIO = 0x08,
+ FLV_TAG_TYPE_VIDEO = 0x09,
+ FLV_TAG_TYPE_META = 0x12,
+};
+
+enum
+{
+ FLV_MONO = 0,
+ FLV_STEREO = 1,
+};
+
+enum
+{
+ FLV_SAMPLESSIZE_8BIT = 0,
+ FLV_SAMPLESSIZE_16BIT = 1 << FLV_AUDIO_SAMPLESSIZE_OFFSET,
+};
+
+enum
+{
+ FLV_SAMPLERATE_SPECIAL = 0, /**< signifies 5512Hz and 8000Hz in the case of NELLYMOSER */
+ FLV_SAMPLERATE_11025HZ = 1 << FLV_AUDIO_SAMPLERATE_OFFSET,
+ FLV_SAMPLERATE_22050HZ = 2 << FLV_AUDIO_SAMPLERATE_OFFSET,
+ FLV_SAMPLERATE_44100HZ = 3 << FLV_AUDIO_SAMPLERATE_OFFSET,
+};
+
+enum
+{
+ FLV_CODECID_MP3 = 2 << FLV_AUDIO_CODECID_OFFSET,
+ FLV_CODECID_AAC = 10<< FLV_AUDIO_CODECID_OFFSET,
+};
+
+enum
+{
+ FLV_CODECID_H264 = 7,
+};
+
+enum
+{
+ FLV_FRAME_KEY = 1 << FLV_VIDEO_FRAMETYPE_OFFSET | 7,
+ FLV_FRAME_INTER = 2 << FLV_VIDEO_FRAMETYPE_OFFSET | 7,
+};
+
+typedef enum
+{
+ AMF_DATA_TYPE_NUMBER = 0x00,
+ AMF_DATA_TYPE_BOOL = 0x01,
+ AMF_DATA_TYPE_STRING = 0x02,
+ AMF_DATA_TYPE_OBJECT = 0x03,
+ AMF_DATA_TYPE_NULL = 0x05,
+ AMF_DATA_TYPE_UNDEFINED = 0x06,
+ AMF_DATA_TYPE_REFERENCE = 0x07,
+ AMF_DATA_TYPE_MIXEDARRAY = 0x08,
+ AMF_DATA_TYPE_OBJECT_END = 0x09,
+ AMF_DATA_TYPE_ARRAY = 0x0a,
+ AMF_DATA_TYPE_DATE = 0x0b,
+ AMF_DATA_TYPE_LONG_STRING = 0x0c,
+ AMF_DATA_TYPE_UNSUPPORTED = 0x0d,
+} AMFDataType;
+
+typedef struct flv_buffer
+{
+ uint8_t *data;
+ unsigned d_cur;
+ unsigned d_max;
+ FILE *fp;
+ uint64_t d_total;
+} flv_buffer;
+
+flv_buffer *flv_create_writer( const char *filename );
+int flv_append_data( flv_buffer *c, uint8_t *data, unsigned size );
+int flv_write_byte( flv_buffer *c, uint8_t *byte );
+int flv_flush_data( flv_buffer *c );
+void rewrite_amf_be24( flv_buffer *c, unsigned length, unsigned start );
+
+uint64_t dbl2int( double value );
+uint64_t get_amf_double( double value );
+void put_byte( flv_buffer *c, uint8_t b );
+void put_be32( flv_buffer *c, uint32_t val );
+void put_be64( flv_buffer *c, uint64_t val );
+void put_be16( flv_buffer *c, uint16_t val );
+void put_be24( flv_buffer *c, uint32_t val );
+void put_tag( flv_buffer *c, const char *tag );
+void put_amf_string( flv_buffer *c, const char *str );
+void put_amf_double( flv_buffer *c, double d );
+
+#endif
return 0;
}
-static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size )
+static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture )
{
mkv_hnd_t *p_mkv = handle;
uint8_t type = p_nalu[4] & 0x1f;
return 0;
}
-static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size )
+static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture )
{
mp4_hnd_t *p_mp4 = handle;
GF_AVCConfigSlot *p_slot;
{
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 (*write_nalu)( hnd_t handle, uint8_t *p_nal, int i_size, x264_picture_t *p_picture );
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;
+extern cli_output_t flv_output;
#endif
return 0;
}
-static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size )
+static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture )
{
if( fwrite( p_nalu, i_size, 1, (FILE*)handle ) > 0 )
return i_size;
/* i/o modules that work with pipes (and fifos) */
static const char * const stdin_format_names[] = { "yuv", "y4m", 0 };
-static const char * const stdout_format_names[] = { "raw", "mkv", 0 };
+static const char * const stdout_format_names[] = { "raw", "mkv", "flv", 0 };
static void Help( x264_param_t *defaults, int longhelp );
static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt );
"Outfile type is selected by filename:\n"
" .264 -> Raw bytestream\n"
" .mkv -> Matroska\n"
+ " .flv -> Flash Video\n"
" .mp4 -> MP4 if compiled with GPAC support (%s)\n"
"\n"
"Options:\n"
H0( "\n" );
H0( " -o, --output Specify output file\n" );
H1( " --stdout Specify stdout format [\"%s\"]\n"
- " - raw, mkv\n", stdout_format_names[0] );
+ " - raw, mkv, flv\n", stdout_format_names[0] );
H1( " --stdin Specify stdin format [\"%s\"]\n"
" - yuv, y4m\n", stdin_format_names[0] );
H0( " --sar width:height Specify Sample Aspect Ratio\n" );
{0, 0, 0, 0}
};
-static int select_output( char *filename, const char *pipe_format )
+static int select_output( char *filename, const char *pipe_format, x264_param_t *param )
{
char *ext = filename + strlen( filename ) - 1;
while( *ext != '.' && ext > filename )
if( !strcasecmp( ext, ".mp4" ) )
{
#ifdef MP4_OUTPUT
- output = mp4_output;
+ output = mp4_output; // FIXME use b_annexb=0
#else
fprintf( stderr, "x264 [error]: not compiled with MP4 output support\n" );
return -1;
#endif
}
else if( !strcasecmp( ext, ".mkv" ) || (!strcmp( filename, "-" ) && !strcasecmp( pipe_format, "mkv" )) )
- output = mkv_output;
+ output = mkv_output; // FIXME use b_annexb=0
+ else if( !strcasecmp( ext, ".flv" ) || (!strcmp( filename, "-" ) && !strcasecmp( pipe_format, "flv" )) )
+ {
+ output = flv_output;
+ param->b_annexb = 0;
+ }
else
output = raw_output;
return 0;
}
input_filename = argv[optind++];
- if( select_output( output_filename, stdout_format ) )
+ if( select_output( output_filename, stdout_format, param ) )
return -1;
if( output.open_file( output_filename, &opt->hout ) )
{
for( i = 0; i < i_nal; i++ )
{
- i_nalu_size = output.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, &pic_out );
if( i_nalu_size < 0 )
return -1;
i_file += i_nalu_size;