Index: configure =================================================================== --- configure (revision 503) +++ configure (working copy) @@ -8,6 +8,7 @@ echo "" echo " --help print this message" echo " --enable-avis-input enables avisynth input (win32 only)" +echo " --enable-ffmpeg-input enables ffmpeg supported input formats" echo " --enable-mp4-output enables mp4 output (using gpac)" echo " --enable-vfw compiles the VfW frontend" echo " --enable-pthread enables multithreaded encoding" @@ -45,6 +46,7 @@ DEVNULL='/dev/null' avis_input="auto" +ffmpeg_input="auto" mp4_output="auto" pthread="auto" debug="no" @@ -209,6 +211,12 @@ --disable-avis-input) avis_input="no" ;; + --enable-ffmpeg-input) + ffmpeg_input="yes" + ;; + --disable-ffmpeg-input) + ffmpeg_input="no" + ;; --enable-mp4-output) mp4_output="yes" ;; @@ -310,11 +318,21 @@ avis_input="no"; fi fi + if [ "$avis_input" = "yes" ] ; then echo "#define AVIS_INPUT" >> config.h LDFLAGS="$LDFLAGS -lvfw32" fi +if [ "$ffmpeg_input" = "auto" ] ; then + ffmpeg_input="no"; +fi + +if [ "$ffmpeg_input" = "yes" ] ; then + echo "#define FFMPEG_INPUT" >> config.h + LDFLAGS="$LDFLAGS `pkg-config libavformat --libs`" +fi + if [ "$pic" = "yes" ] ; then CFLAGS="$CFLAGS -fPIC" ASFLAGS="$ASFLAGS -D__PIC__" @@ -405,17 +423,18 @@ EOF -echo "Platform: $ARCH" -echo "System: $SYS" -echo "avis input: $avis_input" -echo "mp4 output: $mp4_output" -echo "pthread: $pthread" -echo "vfw: $vfw" -echo "debug: $debug" -echo "gprof: $gprof" -echo "PIC: $pic" -echo "shared: $shared" -echo "visualize: $vis" +echo "Platform: $ARCH" +echo "System: $SYS" +echo "avis input: $avis_input" +echo "ffmpeg input: $ffmpeg_input" +echo "mp4 output: $mp4_output" +echo "pthread: $pthread" +echo "vfw: $vfw" +echo "debug: $debug" +echo "gprof: $gprof" +echo "PIC: $pic" +echo "shared: $shared" +echo "visualize: $vis" echo echo "You can run 'make' or 'make fprofiled' now." Index: x264.c =================================================================== --- x264.c (revision 503) +++ x264.c (working copy) @@ -135,6 +135,8 @@ "Infile can be raw YUV 4:2:0 (in which case resolution is required),\n" " or YUV4MPEG 4:2:0 (*.y4m),\n" " or AVI or Avisynth if compiled with AVIS support (%s).\n" + " or any ffmpeg supported formats if compiled with\n" + " libavcodec/libavformat support (%s).\n" "Outfile type is selected by filename:\n" " .264 -> Raw bytestream\n" " .mkv -> Matroska\n" @@ -283,6 +285,11 @@ #else "no", #endif +#ifdef FFMPEG_INPUT + "yes", +#else + "no", +#endif #ifdef MP4_OUTPUT "yes", #else @@ -362,6 +369,7 @@ x264_param_t defaults = *param; char *psz; int b_avis = 0; + int b_other = 0; int b_y4m = 0; int b_thread_input = 0; @@ -953,11 +961,20 @@ while( psz > psz_filename && *psz != '.' ) psz--; - if( !strncasecmp( psz, ".avi", 4 ) || !strncasecmp( psz, ".avs", 4 ) ) - b_avis = 1; if( !strncasecmp( psz, ".y4m", 4 ) ) b_y4m = 1; - if( !(b_avis || b_y4m) && ( !param->i_width || !param->i_height ) ) + +#ifdef AVIS_INPUT + else if( !strncasecmp( psz, ".avs", 4 ) ) + b_avis = 1; +#endif + +#ifdef FFMPEG_INPUT + else + b_other = 1; +#endif + + if( !(b_avis || b_y4m || b_other) && ( !param->i_width || !param->i_height ) ) { Help( &defaults ); return -1; @@ -966,24 +983,39 @@ /* open the input */ { - if( b_avis ) + + 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; + } + #ifdef AVIS_INPUT + else if( b_avis ) + { 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; -#else - fprintf( stderr, "not compiled with AVIS input support\n" ); - return -1; + } #endif + +#ifdef FFMPEG_INPUT + else if( b_other ) + { + p_open_infile = open_file_ffmpeg; + p_get_frame_total = get_frame_total_ffmpeg; + p_read_frame = read_frame_ffmpeg; + p_close_infile = close_file_ffmpeg; } - if ( b_y4m ) +#endif + + else { - 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; + fprintf( stderr, "not compiled with avisynth or ffmpeg input support\n" ); + return -1; } if( p_open_infile( psz_filename, &opt->hin, param ) ) Index: muxers.c =================================================================== --- muxers.c (revision 503) +++ muxers.c (working copy) @@ -39,6 +39,11 @@ #include #endif +#ifdef FFMPEG_INPUT +#include +#include +#endif + #ifdef MP4_OUTPUT #include #endif @@ -417,6 +422,193 @@ #endif +/* support for ffmpeg libavcodec/libavformat supported input files */ + +#ifdef FFMPEG_INPUT +typedef struct { + AVFormatContext *pFormatCtx; + AVStream *pStream; + AVCodecContext *pCodecCtx; + AVCodec *pCodec; + AVFrame *pFrame; + AVFrame *pFrameYUV420P; + AVPacket packet; + int bytesRemaining; + int videoStream; + unsigned char *rawData; + int width, height; + unsigned char *buffer; +} ffmpeg_input_t; + +int open_file_ffmpeg( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param ) +{ + ffmpeg_input_t *handle; + int i; + int numBytes; + + handle = malloc(sizeof(ffmpeg_input_t)); + *p_handle = (hnd_t) handle; + + av_register_all(); + + if( av_open_input_file(&handle->pFormatCtx, psz_filename, NULL, 0, NULL) != 0 ) + return -1; + + if( av_find_stream_info(handle->pFormatCtx) < 0 ) + { + av_close_input_file(handle->pFormatCtx); + return -1; + } + + dump_format(handle->pFormatCtx, 0, psz_filename, 0); + + handle->videoStream = -1; + + for( i = 0; i < handle->pFormatCtx->nb_streams; i++ ) + { + handle->pStream = handle->pFormatCtx->streams[i]; + handle->pCodecCtx = handle->pStream->codec; + + if( handle->pCodecCtx->codec_type == CODEC_TYPE_VIDEO ) + { + handle->videoStream = i; + break; + } + } + + if( handle->videoStream == -1 ) + { + av_close_input_file(handle->pFormatCtx); + return -1; + } + + handle->pCodec = avcodec_find_decoder(handle->pCodecCtx->codec_id); + + if( handle->pCodec == NULL ) + { + av_close_input_file(handle->pFormatCtx); + return -1; + } + + if( handle->pCodec->capabilities & CODEC_CAP_TRUNCATED ) + handle->pCodecCtx->flags |= CODEC_FLAG_TRUNCATED; + + if( avcodec_open(handle->pCodecCtx, handle->pCodec) < 0 ) + { + av_close_input_file(handle->pFormatCtx); + return -1; + } + + handle->width = p_param->i_width = (int) handle->pCodecCtx->width; + handle->height = p_param->i_height = (int) handle->pCodecCtx->height; + + p_param->i_fps_den = handle->pStream->r_frame_rate.den; + p_param->i_fps_num = handle->pStream->r_frame_rate.num; + + handle->pFrame = avcodec_alloc_frame(); + handle->pFrameYUV420P = avcodec_alloc_frame(); + + numBytes = avpicture_get_size(PIX_FMT_YUV420P, handle->pCodecCtx->width, handle->pCodecCtx->height); + handle->buffer = (unsigned char *) malloc(numBytes); + avpicture_fill((AVPicture *) handle->pFrameYUV420P, handle->buffer, PIX_FMT_YUV420P, handle->pCodecCtx->width, + handle->pCodecCtx->height); + + handle->packet.data = NULL; + handle->bytesRemaining = 0; + handle->rawData = NULL; + + return 0; +} + +int get_frame_total_ffmpeg( hnd_t p_handle ) +{ + ffmpeg_input_t *handle; + + handle = (ffmpeg_input_t *) p_handle; + + return (int) handle->pStream->nb_frames; +} + +int read_frame_ffmpeg( x264_picture_t *p_pic, hnd_t p_handle, int i_frame ) +{ + ffmpeg_input_t *handle; + int bytesDecoded, frameFinished; + + handle = (ffmpeg_input_t *) p_handle; + + while( 1 ) + { + while( handle->bytesRemaining > 0 ) + { + bytesDecoded = avcodec_decode_video(handle->pCodecCtx, handle->pFrame, &frameFinished, + handle->rawData, handle->bytesRemaining); + + if( bytesDecoded < 0 ) + return -1; + + handle->bytesRemaining -= bytesDecoded; + handle->rawData += bytesDecoded; + + if( frameFinished ) + goto return_data; + } + + do + { + if( handle->packet.data != NULL ) + av_free_packet(&handle->packet); + + if( av_read_packet(handle->pFormatCtx, &handle->packet) < 0 ) + goto loop_exit; + + } while( handle->packet.stream_index != handle->videoStream); + + handle->bytesRemaining = handle->packet.size; + handle->rawData = handle->packet.data; + } + + +loop_exit: + + bytesDecoded = avcodec_decode_video(handle->pCodecCtx, handle->pFrame, &frameFinished, + handle->rawData, handle->bytesRemaining); + if( handle->packet.data != NULL ) + av_free_packet(&handle->packet); + + if (frameFinished == 0) + return -1; + + +return_data: + + img_convert((AVPicture *) handle->pFrameYUV420P, PIX_FMT_YUV420P, (AVPicture*) handle->pFrame, + handle->pCodecCtx->pix_fmt, handle->pCodecCtx->width, handle->pCodecCtx->height); + + memcpy(p_pic->img.plane[0], handle->pFrameYUV420P->data[0], handle->width * handle->height); + memcpy(p_pic->img.plane[1], handle->pFrameYUV420P->data[1], (handle->width * handle->height) / 4); + memcpy(p_pic->img.plane[2], handle->pFrameYUV420P->data[2], (handle->width * handle->height) / 4); + + return 0; +} + +int close_file_ffmpeg( hnd_t p_handle ) +{ + ffmpeg_input_t *handle; + + handle = (ffmpeg_input_t *) p_handle; + + free(handle->buffer); + av_free(handle->pFrameYUV420P); + + av_free(handle->pFrame); + avcodec_close(handle->pCodecCtx); + av_close_input_file(handle->pFormatCtx); + + return 0; +} +#endif + + #ifdef HAVE_PTHREAD typedef struct { int (*p_read_frame)( x264_picture_t *p_pic, hnd_t handle, int i_frame ); Index: muxers.h =================================================================== --- muxers.h (revision 503) +++ muxers.h (working copy) @@ -20,6 +20,13 @@ int close_file_avis( hnd_t handle ); #endif +#ifdef FFMPEG_INPUT +int open_file_ffmpeg( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param ); +int get_frame_total_ffmpeg( hnd_t p_handle ); +int read_frame_ffmpeg( x264_picture_t *p_pic, hnd_t p_handle, int i_frame ); +int close_file_ffmpeg( hnd_t p_handle ); +#endif + #ifdef HAVE_PTHREAD int open_file_thread( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param ); int get_frame_total_thread( hnd_t handle );