From 7da5daf600f8b97781d85a137c3aa81effb7e610 Mon Sep 17 00:00:00 2001 From: lilo_booter Date: Sun, 28 Dec 2003 12:20:35 +0000 Subject: [PATCH] Added ffmpeg producer git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@27 d19143bc-622f-0410-bfdd-b5b2a6649095 --- mlt/src/framework/mlt_frame.c | 29 +++ mlt/src/framework/mlt_frame.h | 1 + mlt/src/inigo/inigo.c | 41 +++-- mlt/src/modules/Makefile | 2 +- mlt/src/modules/core/factory.c | 2 +- mlt/src/modules/core/producer_ppm.c | 138 +++++++++----- mlt/src/modules/core/producer_ppm.h | 11 -- mlt/src/modules/ffmpeg/Makefile | 27 +++ mlt/src/modules/ffmpeg/configure | 11 ++ mlt/src/modules/ffmpeg/factory.c | 46 +++++ mlt/src/modules/ffmpeg/producer_ffmpeg.c | 291 ++++++++++++++++++++++++++++++ mlt/src/modules/ffmpeg/producer_ffmpeg.h | 29 +++ mlt/src/modules/sdl/consumer_sdl.c | 12 ++- src/framework/mlt_frame.c | 29 +++ src/framework/mlt_frame.h | 1 + src/inigo/inigo.c | 41 +++-- src/modules/Makefile | 2 +- src/modules/core/factory.c | 2 +- src/modules/core/producer_ppm.c | 138 +++++++++----- src/modules/core/producer_ppm.h | 11 -- src/modules/ffmpeg/Makefile | 27 +++ src/modules/ffmpeg/configure | 11 ++ src/modules/ffmpeg/factory.c | 46 +++++ src/modules/ffmpeg/producer_ffmpeg.c | 291 ++++++++++++++++++++++++++++++ src/modules/ffmpeg/producer_ffmpeg.h | 29 +++ src/modules/sdl/consumer_sdl.c | 12 ++- 26 files changed, 1124 insertions(+), 156 deletions(-) create mode 100644 mlt/src/modules/ffmpeg/Makefile create mode 100755 mlt/src/modules/ffmpeg/configure create mode 100644 mlt/src/modules/ffmpeg/factory.c create mode 100644 mlt/src/modules/ffmpeg/producer_ffmpeg.c create mode 100644 mlt/src/modules/ffmpeg/producer_ffmpeg.h create mode 100644 src/modules/ffmpeg/Makefile create mode 100755 src/modules/ffmpeg/configure create mode 100644 src/modules/ffmpeg/factory.c create mode 100644 src/modules/ffmpeg/producer_ffmpeg.c create mode 100644 src/modules/ffmpeg/producer_ffmpeg.h diff --git a/mlt/src/framework/mlt_frame.c b/mlt/src/framework/mlt_frame.c index 6b1558f..69c717b 100644 --- a/mlt/src/framework/mlt_frame.c +++ b/mlt/src/framework/mlt_frame.c @@ -362,6 +362,35 @@ int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride return ret; } +int mlt_convert_yuv420p_to_yuv422( uint8_t *yuv420p, int width, int height, int stride, uint8_t *yuv ) +{ + int ret = 0; + register int i, j; + + int half = width >> 1; + + uint8_t *Y = yuv420p; + uint8_t *U = Y + width * height; + uint8_t *V = U + width * height / 4; + + register uint8_t *d = yuv; + + for ( i = 0; i < height; i++ ) + { + register uint8_t *u = U + ( i / 2 ) * ( half ); + register uint8_t *v = V + ( i / 2 ) * ( half ); + + for ( j = 0; j < half; j++ ) + { + *d ++ = *Y ++; + *d ++ = *u ++; + *d ++ = *Y ++; + *d ++ = *v ++; + } + } + return ret; +} + int mlt_frame_composite_yuv( mlt_frame this, mlt_frame that, int x, int y, float weight ) { int ret = 0; diff --git a/mlt/src/framework/mlt_frame.h b/mlt/src/framework/mlt_frame.h index 35dc53d..94508ec 100644 --- a/mlt/src/framework/mlt_frame.h +++ b/mlt/src/framework/mlt_frame.h @@ -86,6 +86,7 @@ extern void mlt_frame_close( mlt_frame this ); /* convenience functions */ extern int mlt_convert_rgb24a_to_yuv422( uint8_t *rgba, int width, int height, int stride, uint8_t *yuv, uint8_t *alpha ); extern int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride, uint8_t *yuv ); +extern int mlt_convert_yuv420p_to_yuv422( uint8_t *yuv420p, int width, int height, int stride, uint8_t *yuv ); extern int mlt_frame_composite_yuv( mlt_frame this, mlt_frame that, int x, int y, float weight ); extern uint8_t *mlt_frame_resize_yuv422( mlt_frame this, int owidth, int oheight ); extern uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight ); diff --git a/mlt/src/inigo/inigo.c b/mlt/src/inigo/inigo.c index ec6000e..fcb377d 100644 --- a/mlt/src/inigo/inigo.c +++ b/mlt/src/inigo/inigo.c @@ -36,7 +36,7 @@ mlt_producer create_producer( char *file ) // 3rd line fallbacks if ( result == NULL ) - result = mlt_factory_producer( "ppm", file ); + result = mlt_factory_producer( "ffmpeg", file ); return result; } @@ -197,27 +197,38 @@ int main( int argc, char **argv ) } } - // If we have no consumer, default to sdl - if ( consumer == NULL ) - consumer = create_consumer( "sdl", mlt_multitrack_producer( multitrack ) ); - - // Connect producer to playlist + // We must have a producer at this point if ( producer != NULL ) + { + // Connect producer to playlist mlt_playlist_append( playlist, producer ); - // Connect multitrack to producer - mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist ), 0 ); + // If we have no consumer, default to sdl + if ( consumer == NULL ) + consumer = create_consumer( "sdl", mlt_multitrack_producer( multitrack ) ); + + // Connect multitrack to producer + mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist ), 0 ); + + // Connect consumer to tractor + mlt_consumer_connect( consumer, mlt_field_service( field ) ); - // Connect consumer to tractor - mlt_consumer_connect( consumer, mlt_field_service( field ) ); + // Transport functionality + transport( mlt_multitrack_producer( multitrack ) ); - // Transport functionality - transport( mlt_multitrack_producer( multitrack ) ); + // Close the services + mlt_consumer_close( consumer ); + mlt_producer_close( producer ); + } + else + { + fprintf( stderr, "Usage: inigo [ -consumer id[:arg] [ name=value ]* ]\n" + " [ -filter id[:arg] [ name=value ] * ]\n" + " [ producer [ name=value ] * ]+\n" ); + } - // Close the services - mlt_consumer_close( consumer ); + // Close the field mlt_field_close( field ); - mlt_producer_close( producer ); // Close the factory mlt_factory_close( ); diff --git a/mlt/src/modules/Makefile b/mlt/src/modules/Makefile index 3131101..4ed8429 100644 --- a/mlt/src/modules/Makefile +++ b/mlt/src/modules/Makefile @@ -1,4 +1,4 @@ -SUBDIRS = core gtk2 dv sdl mainconcept bluefish +SUBDIRS = core gtk2 dv sdl mainconcept bluefish ffmpeg all clean depend install: list='$(SUBDIRS)'; \ diff --git a/mlt/src/modules/core/factory.c b/mlt/src/modules/core/factory.c index b85d8d7..33fe9ea 100644 --- a/mlt/src/modules/core/factory.c +++ b/mlt/src/modules/core/factory.c @@ -20,11 +20,11 @@ #include +#include "producer_ppm.h" #include "filter_deinterlace.h" #include "filter_greyscale.h" #include "filter_resize.h" #include "filter_gamma.h" -#include "producer_ppm.h" #include "transition_composite.h" void *mlt_create_producer( char *id, void *arg ) diff --git a/mlt/src/modules/core/producer_ppm.c b/mlt/src/modules/core/producer_ppm.c index ca19471..3d3f583 100644 --- a/mlt/src/modules/core/producer_ppm.c +++ b/mlt/src/modules/core/producer_ppm.c @@ -23,6 +23,17 @@ #include #include +typedef struct producer_ppm_s *producer_ppm; + +struct producer_ppm_s +{ + struct mlt_producer_s parent; + char *command; + FILE *video; + FILE *audio; + uint64_t expected; +}; + static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); @@ -50,59 +61,50 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma // Get the frames properties mlt_properties properties = mlt_frame_properties( this ); - // Get the RGB image - uint8_t *rgb = mlt_properties_get_data( properties, "image", NULL ); + if ( mlt_properties_get_int( properties, "has_image" ) ) + { + // Get the RGB image + uint8_t *rgb = mlt_properties_get_data( properties, "image", NULL ); - // Get width and height - *width = mlt_properties_get_int( properties, "width" ); - *height = mlt_properties_get_int( properties, "height" ); + // Get width and height + *width = mlt_properties_get_int( properties, "width" ); + *height = mlt_properties_get_int( properties, "height" ); - // Convert to requested format - if ( *format == mlt_image_yuv422 ) - { - uint8_t *image = malloc( *width * *height * 2 ); - mlt_convert_rgb24_to_yuv422( rgb, *width, *height, *width * 3, image ); - mlt_properties_set_data( properties, "image", image, *width * *height * 2, free, NULL ); - *buffer = image; + // Convert to requested format + if ( *format == mlt_image_yuv422 ) + { + uint8_t *image = malloc( *width * *height * 2 ); + mlt_convert_rgb24_to_yuv422( rgb, *width, *height, *width * 3, image ); + mlt_properties_set_data( properties, "image", image, *width * *height * 2, free, NULL ); + *buffer = image; + } + else if ( *format == mlt_image_rgb24 ) + { + *buffer = rgb; + } } - else if ( *format == mlt_image_rgb24 ) + else { - *buffer = rgb; + mlt_frame_get_image( this, buffer, format, width, height, writable ); } return 0; } -static void producer_ppm_position( producer_ppm this, uint64_t requested ) -{ - if ( requested != this->expected ) - { - if ( this->video != NULL ) - pclose( this->video ); - this->video = NULL; - if ( this->audio != NULL ) - pclose( this->audio ); - this->audio = NULL; - } - - // This is the next frame we expect - this->expected = mlt_producer_frame( &this->parent ) + 1; -} - FILE *producer_ppm_run_video( producer_ppm this ) { if ( this->video == NULL ) { if ( this->command == NULL ) { - this->video = popen( "image2raw -n -a -r 3 -ppm /usr/share/pixmaps/*.png", "r" ); + this->video = popen( "image2raw -k -r 25 -ppm /usr/share/pixmaps/*.png", "r" ); } else { char command[ 1024 ]; float fps = mlt_producer_get_fps( &this->parent ); float position = mlt_producer_position( &this->parent ); - sprintf( command, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -img ppm -", this->command, position, fps ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -img ppm - 2>/dev/null", this->command, position, fps ); this->video = popen( command, "r" ); } } @@ -117,13 +119,35 @@ FILE *producer_ppm_run_audio( producer_ppm this ) { char command[ 1024 ]; float position = mlt_producer_position( &this->parent ); - sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 -", this->command, position ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 - 2>/dev/null", this->command, position ); this->audio = popen( command, "r" ); } } return this->audio; } +static void producer_ppm_position( producer_ppm this, uint64_t requested ) +{ + if ( requested != this->expected ) + { + if ( this->video != NULL ) + pclose( this->video ); + this->video = NULL; + if ( this->audio != NULL ) + pclose( this->audio ); + this->audio = NULL; + } + + // This is the next frame we expect + this->expected = mlt_producer_frame( &this->parent ) + 1; + + // Open the pipe + this->video = producer_ppm_run_video( this ); + + // Open the audio pipe + this->audio = producer_ppm_run_audio( this ); + +} static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { @@ -143,7 +167,10 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma *buffer = malloc( size ); // Read it - fread( *buffer, size, 1, pipe ); + if ( pipe != NULL ) + fread( *buffer, size, 1, pipe ); + else + memset( *buffer, 0, size ); // Pass the data on the frame properties mlt_properties_set_data( properties, "audio", *buffer, size, free, NULL ); @@ -151,6 +178,19 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma return 0; } +static int read_ppm_header( FILE *video, int *width, int *height ) +{ + int count = 0; + { + char temp[ 132 ]; + fgets( temp, 132, video ); + fgets( temp, 132, video ); + count += sscanf( temp, "%d %d", width, height ); + fgets( temp, 132, video ); + } + return count; +} + static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_ppm this = producer->child; @@ -163,18 +203,16 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Are we at the position expected? producer_ppm_position( this, mlt_producer_frame( producer ) ); - // Open the pipe - FILE *video = producer_ppm_run_video( this ); - - // Open the audio pipe - FILE *audio = producer_ppm_run_audio( this ); - // Get the frames properties mlt_properties properties = mlt_frame_properties( *frame ); + FILE *video = this->video; + FILE *audio = this->audio; + // Read the video - if ( video != NULL && fscanf( video, "P6\n%d %d\n255\n", &width, &height ) == 2 ) + if ( video != NULL && read_ppm_header( video, &width, &height ) == 2 ) { + // Allocate an image uint8_t *image = malloc( width * height * 3 ); @@ -185,21 +223,23 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i mlt_properties_set_data( properties, "image", image, width * height * 3, free, NULL ); mlt_properties_set_int( properties, "width", width ); mlt_properties_set_int( properties, "height", height ); + mlt_properties_set_int( properties, "has_image", 1 ); // Push the image callback mlt_frame_push_get_image( *frame, producer_get_image ); } - - // Read the audio - if ( audio != NULL ) + else { - // Set the audio pipe - mlt_properties_set_data( properties, "audio.pipe", audio, 0, NULL, NULL ); - - // Hmm - register audio callback - ( *frame )->get_audio = producer_get_audio; + // Push the image callback + mlt_frame_push_get_image( *frame, producer_get_image ); } + // Set the audio pipe + mlt_properties_set_data( properties, "audio.pipe", audio, 0, NULL, NULL ); + + // Hmm - register audio callback + ( *frame )->get_audio = producer_get_audio; + // Update timecode on the frame we're creating mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) ); diff --git a/mlt/src/modules/core/producer_ppm.h b/mlt/src/modules/core/producer_ppm.h index 69a253a..205d546 100644 --- a/mlt/src/modules/core/producer_ppm.h +++ b/mlt/src/modules/core/producer_ppm.h @@ -24,17 +24,6 @@ #include #include -typedef struct producer_ppm_s *producer_ppm; - -struct producer_ppm_s -{ - struct mlt_producer_s parent; - char *command; - FILE *video; - FILE *audio; - uint64_t expected; -}; - extern mlt_producer producer_ppm_init( void *command ); #endif diff --git a/mlt/src/modules/ffmpeg/Makefile b/mlt/src/modules/ffmpeg/Makefile new file mode 100644 index 0000000..7e6b4d0 --- /dev/null +++ b/mlt/src/modules/ffmpeg/Makefile @@ -0,0 +1,27 @@ + +TARGET = ../libmltffmpeg.so + +OBJS = factory.o \ + producer_ffmpeg.o + +CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread + +SRCS := $(OBJS:.o=.c) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) -shared -o $@ $(OBJS) $(LDFLAGS) + +depend: $(SRCS) + $(CC) -MM $(CFLAGS) $^ 1>.depend + +dist-clean: clean + rm -f .depend + +clean: + rm -f $(OBJS) $(TARGET) + +ifneq ($(wildcard .depend),) +include .depend +endif diff --git a/mlt/src/modules/ffmpeg/configure b/mlt/src/modules/ffmpeg/configure new file mode 100755 index 0000000..e4e7f8d --- /dev/null +++ b/mlt/src/modules/ffmpeg/configure @@ -0,0 +1,11 @@ +#!/bin/bash + +if [ "$help" != "1" ] +then + +cat << EOF >> ../producers.dat +ffmpeg libmltffmpeg.so +EOF + +fi + diff --git a/mlt/src/modules/ffmpeg/factory.c b/mlt/src/modules/ffmpeg/factory.c new file mode 100644 index 0000000..5498e55 --- /dev/null +++ b/mlt/src/modules/ffmpeg/factory.c @@ -0,0 +1,46 @@ +/* + * factory.c -- the factory method interfaces + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "producer_ffmpeg.h" + +void *mlt_create_producer( char *id, void *arg ) +{ + if ( !strcmp( id, "ffmpeg" ) ) + return producer_ffmpeg_init( arg ); + return NULL; +} + +void *mlt_create_filter( char *id, void *arg ) +{ + return NULL; +} + +void *mlt_create_transition( char *id, void *arg ) +{ + return NULL; +} + +void *mlt_create_consumer( char *id, void *arg ) +{ + return NULL; +} + diff --git a/mlt/src/modules/ffmpeg/producer_ffmpeg.c b/mlt/src/modules/ffmpeg/producer_ffmpeg.c new file mode 100644 index 0000000..9e2eed0 --- /dev/null +++ b/mlt/src/modules/ffmpeg/producer_ffmpeg.c @@ -0,0 +1,291 @@ +/* + * producer_ffmpeg.c -- simple ffmpeg test case + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "producer_ffmpeg.h" +#include +#include +#include + +typedef struct producer_ffmpeg_s *producer_ffmpeg; + +struct producer_ffmpeg_s +{ + struct mlt_producer_s parent; + char *command; + FILE *video; + FILE *audio; + uint64_t expected; + uint8_t *buffer; + int open; + int width; + int height; +}; + +static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); +static void producer_close( mlt_producer parent ); + +mlt_producer producer_ffmpeg_init( char *command ) +{ + producer_ffmpeg this = calloc( sizeof( struct producer_ffmpeg_s ), 1 ); + if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) + { + mlt_producer producer = &this->parent; + + producer->get_frame = producer_get_frame; + producer->close = producer_close; + + if ( command != NULL ) + this->command = strdup( command ); + + this->buffer = malloc( 1024 * 1024 ); + + return producer; + } + free( this ); + return NULL; +} + +static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) +{ + // Get the frames properties + mlt_properties properties = mlt_frame_properties( this ); + + if ( mlt_properties_get_int( properties, "has_image" ) ) + { + // Get width and height + *format = mlt_image_yuv422; + *width = mlt_properties_get_int( properties, "width" ); + *height = mlt_properties_get_int( properties, "height" ); + + // Specify format and image + *buffer = mlt_properties_get_data( properties, "image", NULL ); + } + else + { + mlt_frame_get_image( this, buffer, format, width, height, writable ); + } + + return 0; +} + +FILE *producer_ffmpeg_run_video( producer_ffmpeg this ) +{ + if ( this->video == NULL && !this->open ) + { + if ( this->command != NULL ) + { + char command[ 1024 ]; + float fps = mlt_producer_get_fps( &this->parent ); + float position = mlt_producer_position( &this->parent ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -f yuv4mpegpipe - 2>/dev/null", this->command, position, fps ); + this->video = popen( command, "r" ); + } + } + return this->video; +} + +FILE *producer_ffmpeg_run_audio( producer_ffmpeg this ) +{ + if ( this->audio == NULL && !this->open ) + { + if ( this->command != NULL ) + { + char command[ 1024 ]; + float position = mlt_producer_position( &this->parent ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 - 2>/dev/null", this->command, position ); + this->audio = popen( command, "r" ); + } + } + return this->audio; +} + +static void producer_ffmpeg_position( producer_ffmpeg this, uint64_t requested ) +{ + if ( requested != this->expected ) + { + if ( this->video != NULL ) + pclose( this->video ); + this->video = NULL; + if ( this->audio != NULL ) + pclose( this->audio ); + this->audio = NULL; + + // We should not be open now + this->open = 0; + } + + // This is the next frame we expect + this->expected = mlt_producer_frame( &this->parent ) + 1; + + // Open the pipe + this->video = producer_ffmpeg_run_video( this ); + + // Open the audio pipe + this->audio = producer_ffmpeg_run_audio( this ); + + // We should be open now + this->open = 1; +} + +static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +{ + // Get the frames properties + mlt_properties properties = mlt_frame_properties( this ); + + producer_ffmpeg producer = mlt_properties_get_data( properties, "producer_ffmpeg", NULL ); + + *frequency = 48000; + *channels = 2; + *samples = 1920; + + // Size + int size = *samples * *channels * 2; + + // Allocate an image + *buffer = malloc( size ); + + // Read it + if ( producer->audio != NULL ) + { + if ( fread( *buffer, size, 1, producer->audio ) != 1 ) + { + pclose( producer->audio ); + producer->audio = NULL; + } + } + else + { + memset( *buffer, 0, size ); + } + + // Pass the data on the frame properties + mlt_properties_set_data( properties, "audio", *buffer, size, free, NULL ); + + return 0; +} + +static int read_ffmpeg_header( producer_ffmpeg this, int *width, int *height ) +{ + int count = 0; + char temp[ 132 ]; + FILE *video = this->video; + + if ( fgets( temp, 132, video ) ) + { + if ( strncmp( temp, "FRAME", 5 ) ) + { + if ( strstr( temp, " W" ) != NULL ) + *width = atoi( strstr( temp, " W" ) + 2 ); + if ( strstr( temp, " H" ) != NULL ) + *height = atoi( strstr( temp, " H" ) + 2 ); + count = 2; + fgets( temp, 132, video ); + this->width = *width; + this->height = *height; + } + else + { + *width = this->width; + *height = this->height; + count = 2; + } + } + return count; +} + +static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) +{ + producer_ffmpeg this = producer->child; + int width; + int height; + + // Construct a test frame + *frame = mlt_frame_init( ); + + // Are we at the position expected? + producer_ffmpeg_position( this, mlt_producer_frame( producer ) ); + + // Get the frames properties + mlt_properties properties = mlt_frame_properties( *frame ); + + FILE *video = this->video; + + // Read the video + if ( video != NULL && read_ffmpeg_header( this, &width, &height ) == 2 ) + { + // Allocate an image + uint8_t *image = malloc( width * height * 2 ); + + // Read it + fread( this->buffer, width * height * 3 / 2, 1, video ); + + // Convert it + mlt_convert_yuv420p_to_yuv422( this->buffer, width, height, width, image ); + + // Pass the data on the frame properties + mlt_properties_set_data( properties, "image", image, width * height * 2, free, NULL ); + mlt_properties_set_int( properties, "width", width ); + mlt_properties_set_int( properties, "height", height ); + mlt_properties_set_int( properties, "has_image", 1 ); + + // Push the image callback + mlt_frame_push_get_image( *frame, producer_get_image ); + } + else + { + // Clean up + if ( this->video != NULL ) + { + pclose( this->video ); + this->video = NULL; + } + + // Push the image callback + mlt_frame_push_get_image( *frame, producer_get_image ); + } + + // Set the audio pipe + mlt_properties_set_data( properties, "producer_ffmpeg", this, 0, NULL, NULL ); + + // Hmm - register audio callback + ( *frame )->get_audio = producer_get_audio; + + // Update timecode on the frame we're creating + mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) ); + + // Calculate the next timecode + mlt_producer_prepare_next( producer ); + + return 0; +} + +static void producer_close( mlt_producer parent ) +{ + producer_ffmpeg this = parent->child; + if ( this->video ) + pclose( this->video ); + if ( this->audio ) + pclose( this->audio ); + free( this->command ); + parent->close = NULL; + mlt_producer_close( parent ); + free( this ); +} + diff --git a/mlt/src/modules/ffmpeg/producer_ffmpeg.h b/mlt/src/modules/ffmpeg/producer_ffmpeg.h new file mode 100644 index 0000000..a80470b --- /dev/null +++ b/mlt/src/modules/ffmpeg/producer_ffmpeg.h @@ -0,0 +1,29 @@ +/* + * producer_ffmpeg.h -- simple ffmpeg test case + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _PRODUCER_Y4M_H_ +#define _PRODUCER_Y4M_H_ + +#include +#include + +extern mlt_producer producer_ffmpeg_init( char *file ); + +#endif diff --git a/mlt/src/modules/sdl/consumer_sdl.c b/mlt/src/modules/sdl/consumer_sdl.c index cf02c73..59a9b02 100644 --- a/mlt/src/modules/sdl/consumer_sdl.c +++ b/mlt/src/modules/sdl/consumer_sdl.c @@ -234,7 +234,7 @@ static void *consumer_thread( void *arg ) request.freq = frequency; request.format = AUDIO_S16; request.channels = channels; - request.samples = 512; + request.samples = 2048; request.callback = sdl_fill_audio; request.userdata = (void *)this; if ( SDL_OpenAudio( &request, NULL ) < 0 ) @@ -282,12 +282,22 @@ static void *consumer_thread( void *arg ) break; } } + + if ( width != this->width || height != this->height ) + { + this->width = width; + this->height = height; + changed = 1; + } } if ( sdl_screen == NULL || changed ) { double aspect_ratio = mlt_frame_get_aspect_ratio( frame ); + if ( mlt_properties_get_double( properties, "aspect_ratio" ) ) + aspect_ratio = mlt_properties_get_double( properties, "aspect_ratio" ); + if ( this->window_width == 0 || this->window_height == 0 ) { this->window_width = width; diff --git a/src/framework/mlt_frame.c b/src/framework/mlt_frame.c index 6b1558f..69c717b 100644 --- a/src/framework/mlt_frame.c +++ b/src/framework/mlt_frame.c @@ -362,6 +362,35 @@ int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride return ret; } +int mlt_convert_yuv420p_to_yuv422( uint8_t *yuv420p, int width, int height, int stride, uint8_t *yuv ) +{ + int ret = 0; + register int i, j; + + int half = width >> 1; + + uint8_t *Y = yuv420p; + uint8_t *U = Y + width * height; + uint8_t *V = U + width * height / 4; + + register uint8_t *d = yuv; + + for ( i = 0; i < height; i++ ) + { + register uint8_t *u = U + ( i / 2 ) * ( half ); + register uint8_t *v = V + ( i / 2 ) * ( half ); + + for ( j = 0; j < half; j++ ) + { + *d ++ = *Y ++; + *d ++ = *u ++; + *d ++ = *Y ++; + *d ++ = *v ++; + } + } + return ret; +} + int mlt_frame_composite_yuv( mlt_frame this, mlt_frame that, int x, int y, float weight ) { int ret = 0; diff --git a/src/framework/mlt_frame.h b/src/framework/mlt_frame.h index 35dc53d..94508ec 100644 --- a/src/framework/mlt_frame.h +++ b/src/framework/mlt_frame.h @@ -86,6 +86,7 @@ extern void mlt_frame_close( mlt_frame this ); /* convenience functions */ extern int mlt_convert_rgb24a_to_yuv422( uint8_t *rgba, int width, int height, int stride, uint8_t *yuv, uint8_t *alpha ); extern int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride, uint8_t *yuv ); +extern int mlt_convert_yuv420p_to_yuv422( uint8_t *yuv420p, int width, int height, int stride, uint8_t *yuv ); extern int mlt_frame_composite_yuv( mlt_frame this, mlt_frame that, int x, int y, float weight ); extern uint8_t *mlt_frame_resize_yuv422( mlt_frame this, int owidth, int oheight ); extern uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight ); diff --git a/src/inigo/inigo.c b/src/inigo/inigo.c index ec6000e..fcb377d 100644 --- a/src/inigo/inigo.c +++ b/src/inigo/inigo.c @@ -36,7 +36,7 @@ mlt_producer create_producer( char *file ) // 3rd line fallbacks if ( result == NULL ) - result = mlt_factory_producer( "ppm", file ); + result = mlt_factory_producer( "ffmpeg", file ); return result; } @@ -197,27 +197,38 @@ int main( int argc, char **argv ) } } - // If we have no consumer, default to sdl - if ( consumer == NULL ) - consumer = create_consumer( "sdl", mlt_multitrack_producer( multitrack ) ); - - // Connect producer to playlist + // We must have a producer at this point if ( producer != NULL ) + { + // Connect producer to playlist mlt_playlist_append( playlist, producer ); - // Connect multitrack to producer - mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist ), 0 ); + // If we have no consumer, default to sdl + if ( consumer == NULL ) + consumer = create_consumer( "sdl", mlt_multitrack_producer( multitrack ) ); + + // Connect multitrack to producer + mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist ), 0 ); + + // Connect consumer to tractor + mlt_consumer_connect( consumer, mlt_field_service( field ) ); - // Connect consumer to tractor - mlt_consumer_connect( consumer, mlt_field_service( field ) ); + // Transport functionality + transport( mlt_multitrack_producer( multitrack ) ); - // Transport functionality - transport( mlt_multitrack_producer( multitrack ) ); + // Close the services + mlt_consumer_close( consumer ); + mlt_producer_close( producer ); + } + else + { + fprintf( stderr, "Usage: inigo [ -consumer id[:arg] [ name=value ]* ]\n" + " [ -filter id[:arg] [ name=value ] * ]\n" + " [ producer [ name=value ] * ]+\n" ); + } - // Close the services - mlt_consumer_close( consumer ); + // Close the field mlt_field_close( field ); - mlt_producer_close( producer ); // Close the factory mlt_factory_close( ); diff --git a/src/modules/Makefile b/src/modules/Makefile index 3131101..4ed8429 100644 --- a/src/modules/Makefile +++ b/src/modules/Makefile @@ -1,4 +1,4 @@ -SUBDIRS = core gtk2 dv sdl mainconcept bluefish +SUBDIRS = core gtk2 dv sdl mainconcept bluefish ffmpeg all clean depend install: list='$(SUBDIRS)'; \ diff --git a/src/modules/core/factory.c b/src/modules/core/factory.c index b85d8d7..33fe9ea 100644 --- a/src/modules/core/factory.c +++ b/src/modules/core/factory.c @@ -20,11 +20,11 @@ #include +#include "producer_ppm.h" #include "filter_deinterlace.h" #include "filter_greyscale.h" #include "filter_resize.h" #include "filter_gamma.h" -#include "producer_ppm.h" #include "transition_composite.h" void *mlt_create_producer( char *id, void *arg ) diff --git a/src/modules/core/producer_ppm.c b/src/modules/core/producer_ppm.c index ca19471..3d3f583 100644 --- a/src/modules/core/producer_ppm.c +++ b/src/modules/core/producer_ppm.c @@ -23,6 +23,17 @@ #include #include +typedef struct producer_ppm_s *producer_ppm; + +struct producer_ppm_s +{ + struct mlt_producer_s parent; + char *command; + FILE *video; + FILE *audio; + uint64_t expected; +}; + static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); @@ -50,59 +61,50 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma // Get the frames properties mlt_properties properties = mlt_frame_properties( this ); - // Get the RGB image - uint8_t *rgb = mlt_properties_get_data( properties, "image", NULL ); + if ( mlt_properties_get_int( properties, "has_image" ) ) + { + // Get the RGB image + uint8_t *rgb = mlt_properties_get_data( properties, "image", NULL ); - // Get width and height - *width = mlt_properties_get_int( properties, "width" ); - *height = mlt_properties_get_int( properties, "height" ); + // Get width and height + *width = mlt_properties_get_int( properties, "width" ); + *height = mlt_properties_get_int( properties, "height" ); - // Convert to requested format - if ( *format == mlt_image_yuv422 ) - { - uint8_t *image = malloc( *width * *height * 2 ); - mlt_convert_rgb24_to_yuv422( rgb, *width, *height, *width * 3, image ); - mlt_properties_set_data( properties, "image", image, *width * *height * 2, free, NULL ); - *buffer = image; + // Convert to requested format + if ( *format == mlt_image_yuv422 ) + { + uint8_t *image = malloc( *width * *height * 2 ); + mlt_convert_rgb24_to_yuv422( rgb, *width, *height, *width * 3, image ); + mlt_properties_set_data( properties, "image", image, *width * *height * 2, free, NULL ); + *buffer = image; + } + else if ( *format == mlt_image_rgb24 ) + { + *buffer = rgb; + } } - else if ( *format == mlt_image_rgb24 ) + else { - *buffer = rgb; + mlt_frame_get_image( this, buffer, format, width, height, writable ); } return 0; } -static void producer_ppm_position( producer_ppm this, uint64_t requested ) -{ - if ( requested != this->expected ) - { - if ( this->video != NULL ) - pclose( this->video ); - this->video = NULL; - if ( this->audio != NULL ) - pclose( this->audio ); - this->audio = NULL; - } - - // This is the next frame we expect - this->expected = mlt_producer_frame( &this->parent ) + 1; -} - FILE *producer_ppm_run_video( producer_ppm this ) { if ( this->video == NULL ) { if ( this->command == NULL ) { - this->video = popen( "image2raw -n -a -r 3 -ppm /usr/share/pixmaps/*.png", "r" ); + this->video = popen( "image2raw -k -r 25 -ppm /usr/share/pixmaps/*.png", "r" ); } else { char command[ 1024 ]; float fps = mlt_producer_get_fps( &this->parent ); float position = mlt_producer_position( &this->parent ); - sprintf( command, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -img ppm -", this->command, position, fps ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -img ppm - 2>/dev/null", this->command, position, fps ); this->video = popen( command, "r" ); } } @@ -117,13 +119,35 @@ FILE *producer_ppm_run_audio( producer_ppm this ) { char command[ 1024 ]; float position = mlt_producer_position( &this->parent ); - sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 -", this->command, position ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 - 2>/dev/null", this->command, position ); this->audio = popen( command, "r" ); } } return this->audio; } +static void producer_ppm_position( producer_ppm this, uint64_t requested ) +{ + if ( requested != this->expected ) + { + if ( this->video != NULL ) + pclose( this->video ); + this->video = NULL; + if ( this->audio != NULL ) + pclose( this->audio ); + this->audio = NULL; + } + + // This is the next frame we expect + this->expected = mlt_producer_frame( &this->parent ) + 1; + + // Open the pipe + this->video = producer_ppm_run_video( this ); + + // Open the audio pipe + this->audio = producer_ppm_run_audio( this ); + +} static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { @@ -143,7 +167,10 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma *buffer = malloc( size ); // Read it - fread( *buffer, size, 1, pipe ); + if ( pipe != NULL ) + fread( *buffer, size, 1, pipe ); + else + memset( *buffer, 0, size ); // Pass the data on the frame properties mlt_properties_set_data( properties, "audio", *buffer, size, free, NULL ); @@ -151,6 +178,19 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma return 0; } +static int read_ppm_header( FILE *video, int *width, int *height ) +{ + int count = 0; + { + char temp[ 132 ]; + fgets( temp, 132, video ); + fgets( temp, 132, video ); + count += sscanf( temp, "%d %d", width, height ); + fgets( temp, 132, video ); + } + return count; +} + static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_ppm this = producer->child; @@ -163,18 +203,16 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Are we at the position expected? producer_ppm_position( this, mlt_producer_frame( producer ) ); - // Open the pipe - FILE *video = producer_ppm_run_video( this ); - - // Open the audio pipe - FILE *audio = producer_ppm_run_audio( this ); - // Get the frames properties mlt_properties properties = mlt_frame_properties( *frame ); + FILE *video = this->video; + FILE *audio = this->audio; + // Read the video - if ( video != NULL && fscanf( video, "P6\n%d %d\n255\n", &width, &height ) == 2 ) + if ( video != NULL && read_ppm_header( video, &width, &height ) == 2 ) { + // Allocate an image uint8_t *image = malloc( width * height * 3 ); @@ -185,21 +223,23 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i mlt_properties_set_data( properties, "image", image, width * height * 3, free, NULL ); mlt_properties_set_int( properties, "width", width ); mlt_properties_set_int( properties, "height", height ); + mlt_properties_set_int( properties, "has_image", 1 ); // Push the image callback mlt_frame_push_get_image( *frame, producer_get_image ); } - - // Read the audio - if ( audio != NULL ) + else { - // Set the audio pipe - mlt_properties_set_data( properties, "audio.pipe", audio, 0, NULL, NULL ); - - // Hmm - register audio callback - ( *frame )->get_audio = producer_get_audio; + // Push the image callback + mlt_frame_push_get_image( *frame, producer_get_image ); } + // Set the audio pipe + mlt_properties_set_data( properties, "audio.pipe", audio, 0, NULL, NULL ); + + // Hmm - register audio callback + ( *frame )->get_audio = producer_get_audio; + // Update timecode on the frame we're creating mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) ); diff --git a/src/modules/core/producer_ppm.h b/src/modules/core/producer_ppm.h index 69a253a..205d546 100644 --- a/src/modules/core/producer_ppm.h +++ b/src/modules/core/producer_ppm.h @@ -24,17 +24,6 @@ #include #include -typedef struct producer_ppm_s *producer_ppm; - -struct producer_ppm_s -{ - struct mlt_producer_s parent; - char *command; - FILE *video; - FILE *audio; - uint64_t expected; -}; - extern mlt_producer producer_ppm_init( void *command ); #endif diff --git a/src/modules/ffmpeg/Makefile b/src/modules/ffmpeg/Makefile new file mode 100644 index 0000000..7e6b4d0 --- /dev/null +++ b/src/modules/ffmpeg/Makefile @@ -0,0 +1,27 @@ + +TARGET = ../libmltffmpeg.so + +OBJS = factory.o \ + producer_ffmpeg.o + +CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread + +SRCS := $(OBJS:.o=.c) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) -shared -o $@ $(OBJS) $(LDFLAGS) + +depend: $(SRCS) + $(CC) -MM $(CFLAGS) $^ 1>.depend + +dist-clean: clean + rm -f .depend + +clean: + rm -f $(OBJS) $(TARGET) + +ifneq ($(wildcard .depend),) +include .depend +endif diff --git a/src/modules/ffmpeg/configure b/src/modules/ffmpeg/configure new file mode 100755 index 0000000..e4e7f8d --- /dev/null +++ b/src/modules/ffmpeg/configure @@ -0,0 +1,11 @@ +#!/bin/bash + +if [ "$help" != "1" ] +then + +cat << EOF >> ../producers.dat +ffmpeg libmltffmpeg.so +EOF + +fi + diff --git a/src/modules/ffmpeg/factory.c b/src/modules/ffmpeg/factory.c new file mode 100644 index 0000000..5498e55 --- /dev/null +++ b/src/modules/ffmpeg/factory.c @@ -0,0 +1,46 @@ +/* + * factory.c -- the factory method interfaces + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "producer_ffmpeg.h" + +void *mlt_create_producer( char *id, void *arg ) +{ + if ( !strcmp( id, "ffmpeg" ) ) + return producer_ffmpeg_init( arg ); + return NULL; +} + +void *mlt_create_filter( char *id, void *arg ) +{ + return NULL; +} + +void *mlt_create_transition( char *id, void *arg ) +{ + return NULL; +} + +void *mlt_create_consumer( char *id, void *arg ) +{ + return NULL; +} + diff --git a/src/modules/ffmpeg/producer_ffmpeg.c b/src/modules/ffmpeg/producer_ffmpeg.c new file mode 100644 index 0000000..9e2eed0 --- /dev/null +++ b/src/modules/ffmpeg/producer_ffmpeg.c @@ -0,0 +1,291 @@ +/* + * producer_ffmpeg.c -- simple ffmpeg test case + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "producer_ffmpeg.h" +#include +#include +#include + +typedef struct producer_ffmpeg_s *producer_ffmpeg; + +struct producer_ffmpeg_s +{ + struct mlt_producer_s parent; + char *command; + FILE *video; + FILE *audio; + uint64_t expected; + uint8_t *buffer; + int open; + int width; + int height; +}; + +static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); +static void producer_close( mlt_producer parent ); + +mlt_producer producer_ffmpeg_init( char *command ) +{ + producer_ffmpeg this = calloc( sizeof( struct producer_ffmpeg_s ), 1 ); + if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) + { + mlt_producer producer = &this->parent; + + producer->get_frame = producer_get_frame; + producer->close = producer_close; + + if ( command != NULL ) + this->command = strdup( command ); + + this->buffer = malloc( 1024 * 1024 ); + + return producer; + } + free( this ); + return NULL; +} + +static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) +{ + // Get the frames properties + mlt_properties properties = mlt_frame_properties( this ); + + if ( mlt_properties_get_int( properties, "has_image" ) ) + { + // Get width and height + *format = mlt_image_yuv422; + *width = mlt_properties_get_int( properties, "width" ); + *height = mlt_properties_get_int( properties, "height" ); + + // Specify format and image + *buffer = mlt_properties_get_data( properties, "image", NULL ); + } + else + { + mlt_frame_get_image( this, buffer, format, width, height, writable ); + } + + return 0; +} + +FILE *producer_ffmpeg_run_video( producer_ffmpeg this ) +{ + if ( this->video == NULL && !this->open ) + { + if ( this->command != NULL ) + { + char command[ 1024 ]; + float fps = mlt_producer_get_fps( &this->parent ); + float position = mlt_producer_position( &this->parent ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -f yuv4mpegpipe - 2>/dev/null", this->command, position, fps ); + this->video = popen( command, "r" ); + } + } + return this->video; +} + +FILE *producer_ffmpeg_run_audio( producer_ffmpeg this ) +{ + if ( this->audio == NULL && !this->open ) + { + if ( this->command != NULL ) + { + char command[ 1024 ]; + float position = mlt_producer_position( &this->parent ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 - 2>/dev/null", this->command, position ); + this->audio = popen( command, "r" ); + } + } + return this->audio; +} + +static void producer_ffmpeg_position( producer_ffmpeg this, uint64_t requested ) +{ + if ( requested != this->expected ) + { + if ( this->video != NULL ) + pclose( this->video ); + this->video = NULL; + if ( this->audio != NULL ) + pclose( this->audio ); + this->audio = NULL; + + // We should not be open now + this->open = 0; + } + + // This is the next frame we expect + this->expected = mlt_producer_frame( &this->parent ) + 1; + + // Open the pipe + this->video = producer_ffmpeg_run_video( this ); + + // Open the audio pipe + this->audio = producer_ffmpeg_run_audio( this ); + + // We should be open now + this->open = 1; +} + +static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +{ + // Get the frames properties + mlt_properties properties = mlt_frame_properties( this ); + + producer_ffmpeg producer = mlt_properties_get_data( properties, "producer_ffmpeg", NULL ); + + *frequency = 48000; + *channels = 2; + *samples = 1920; + + // Size + int size = *samples * *channels * 2; + + // Allocate an image + *buffer = malloc( size ); + + // Read it + if ( producer->audio != NULL ) + { + if ( fread( *buffer, size, 1, producer->audio ) != 1 ) + { + pclose( producer->audio ); + producer->audio = NULL; + } + } + else + { + memset( *buffer, 0, size ); + } + + // Pass the data on the frame properties + mlt_properties_set_data( properties, "audio", *buffer, size, free, NULL ); + + return 0; +} + +static int read_ffmpeg_header( producer_ffmpeg this, int *width, int *height ) +{ + int count = 0; + char temp[ 132 ]; + FILE *video = this->video; + + if ( fgets( temp, 132, video ) ) + { + if ( strncmp( temp, "FRAME", 5 ) ) + { + if ( strstr( temp, " W" ) != NULL ) + *width = atoi( strstr( temp, " W" ) + 2 ); + if ( strstr( temp, " H" ) != NULL ) + *height = atoi( strstr( temp, " H" ) + 2 ); + count = 2; + fgets( temp, 132, video ); + this->width = *width; + this->height = *height; + } + else + { + *width = this->width; + *height = this->height; + count = 2; + } + } + return count; +} + +static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) +{ + producer_ffmpeg this = producer->child; + int width; + int height; + + // Construct a test frame + *frame = mlt_frame_init( ); + + // Are we at the position expected? + producer_ffmpeg_position( this, mlt_producer_frame( producer ) ); + + // Get the frames properties + mlt_properties properties = mlt_frame_properties( *frame ); + + FILE *video = this->video; + + // Read the video + if ( video != NULL && read_ffmpeg_header( this, &width, &height ) == 2 ) + { + // Allocate an image + uint8_t *image = malloc( width * height * 2 ); + + // Read it + fread( this->buffer, width * height * 3 / 2, 1, video ); + + // Convert it + mlt_convert_yuv420p_to_yuv422( this->buffer, width, height, width, image ); + + // Pass the data on the frame properties + mlt_properties_set_data( properties, "image", image, width * height * 2, free, NULL ); + mlt_properties_set_int( properties, "width", width ); + mlt_properties_set_int( properties, "height", height ); + mlt_properties_set_int( properties, "has_image", 1 ); + + // Push the image callback + mlt_frame_push_get_image( *frame, producer_get_image ); + } + else + { + // Clean up + if ( this->video != NULL ) + { + pclose( this->video ); + this->video = NULL; + } + + // Push the image callback + mlt_frame_push_get_image( *frame, producer_get_image ); + } + + // Set the audio pipe + mlt_properties_set_data( properties, "producer_ffmpeg", this, 0, NULL, NULL ); + + // Hmm - register audio callback + ( *frame )->get_audio = producer_get_audio; + + // Update timecode on the frame we're creating + mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) ); + + // Calculate the next timecode + mlt_producer_prepare_next( producer ); + + return 0; +} + +static void producer_close( mlt_producer parent ) +{ + producer_ffmpeg this = parent->child; + if ( this->video ) + pclose( this->video ); + if ( this->audio ) + pclose( this->audio ); + free( this->command ); + parent->close = NULL; + mlt_producer_close( parent ); + free( this ); +} + diff --git a/src/modules/ffmpeg/producer_ffmpeg.h b/src/modules/ffmpeg/producer_ffmpeg.h new file mode 100644 index 0000000..a80470b --- /dev/null +++ b/src/modules/ffmpeg/producer_ffmpeg.h @@ -0,0 +1,29 @@ +/* + * producer_ffmpeg.h -- simple ffmpeg test case + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _PRODUCER_Y4M_H_ +#define _PRODUCER_Y4M_H_ + +#include +#include + +extern mlt_producer producer_ffmpeg_init( char *file ); + +#endif diff --git a/src/modules/sdl/consumer_sdl.c b/src/modules/sdl/consumer_sdl.c index cf02c73..59a9b02 100644 --- a/src/modules/sdl/consumer_sdl.c +++ b/src/modules/sdl/consumer_sdl.c @@ -234,7 +234,7 @@ static void *consumer_thread( void *arg ) request.freq = frequency; request.format = AUDIO_S16; request.channels = channels; - request.samples = 512; + request.samples = 2048; request.callback = sdl_fill_audio; request.userdata = (void *)this; if ( SDL_OpenAudio( &request, NULL ) < 0 ) @@ -282,12 +282,22 @@ static void *consumer_thread( void *arg ) break; } } + + if ( width != this->width || height != this->height ) + { + this->width = width; + this->height = height; + changed = 1; + } } if ( sdl_screen == NULL || changed ) { double aspect_ratio = mlt_frame_get_aspect_ratio( frame ); + if ( mlt_properties_get_double( properties, "aspect_ratio" ) ) + aspect_ratio = mlt_properties_get_double( properties, "aspect_ratio" ); + if ( this->window_width == 0 || this->window_height == 0 ) { this->window_width = width; -- 1.7.4.4