]> git.sesse.net Git - mlt/blob - src/modules/core/producer_ppm.c
A little debugging.
[mlt] / src / modules / core / producer_ppm.c
1 /*
2  * producer_ppm.c -- simple ppm test case
3  * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4  * Author: Charles Yates <charles.yates@pandora.be>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <framework/mlt_producer.h>
22 #include <framework/mlt_frame.h>
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 typedef struct producer_ppm_s *producer_ppm;
28
29 struct producer_ppm_s
30 {
31         struct mlt_producer_s parent;
32         char *command;
33         FILE *video;
34         FILE *audio;
35         uint64_t expected;
36 };
37
38 static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index );
39 static void producer_close( mlt_producer parent );
40
41 mlt_producer producer_ppm_init( mlt_profile profile, mlt_service_type type, const char *id, char *command )
42 {
43         producer_ppm this = calloc( 1, sizeof( struct producer_ppm_s ) );
44         if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 )
45         {
46                 mlt_producer producer = &this->parent;
47                 mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
48
49                 producer->get_frame = producer_get_frame;
50                 producer->close = ( mlt_destructor )producer_close;
51
52                 if ( command != NULL )
53                 {
54                         mlt_properties_set( properties, "resource", command );
55                         this->command = strdup( command );
56                 }
57                 else
58                 {
59                         mlt_properties_set( properties, "resource", "ppm test" );
60                 }
61
62                 return producer;
63         }
64         free( this );
65         return NULL;
66 }
67
68 static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
69 {
70         // Get the frames properties
71         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
72
73         if ( mlt_properties_get_int( properties, "has_image" ) )
74         {
75                 // Get the RGB image
76                 *buffer = mlt_properties_get_data( properties, "image", NULL );
77                 *width = mlt_properties_get_int( properties, "width" );
78                 *height = mlt_properties_get_int( properties, "height" );
79                 *format = mlt_image_rgb24;
80         }
81         else
82         {
83                 mlt_frame_get_image( this, buffer, format, width, height, writable );
84         }
85
86         return 0;
87 }
88
89 FILE *producer_ppm_run_video( producer_ppm this )
90 {
91         if ( this->video == NULL )
92         {
93                 if ( this->command == NULL )
94                 {
95                         this->video = popen( "image2raw -k -r 25 -ppm /usr/share/pixmaps/*.png", "r" );
96                 }
97                 else
98                 {
99                         char command[ 1024 ];
100                         float fps = mlt_producer_get_fps( &this->parent );
101                         float position = mlt_producer_position( &this->parent );
102                         sprintf( command, "ffmpeg -i \"%s\" -ss %f -f image2pipe -r %f -vcodec ppm - 2>/dev/null", this->command, position, fps );
103                         this->video = popen( command, "r" );
104                 }
105         }
106         return this->video;
107 }
108
109 FILE *producer_ppm_run_audio( producer_ppm this )
110 {
111         if ( this->audio == NULL )
112         {
113                 if ( this->command != NULL )
114                 {
115                         char command[ 1024 ];
116                         float position = mlt_producer_position( &this->parent );
117                         sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 - 2>/dev/null", this->command, position );
118                         this->audio = popen( command, "r" );
119                 }
120         }
121         return this->audio;
122 }
123
124 static void producer_ppm_position( producer_ppm this, uint64_t requested )
125 {
126         if ( requested != this->expected )
127         {
128                 if ( this->video != NULL )
129                         pclose( this->video );
130                 this->video = NULL;
131                 if ( this->audio != NULL )
132                         pclose( this->audio );
133                 this->audio = NULL;
134         }
135
136         // This is the next frame we expect
137         this->expected = mlt_producer_frame( &this->parent ) + 1;
138
139         // Open the pipe
140         this->video = producer_ppm_run_video( this );
141
142         // Open the audio pipe
143         this->audio = producer_ppm_run_audio( this );
144
145 }
146
147 static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
148 {
149         // Get the frames properties
150         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
151
152         FILE *pipe = mlt_properties_get_data( properties, "audio.pipe", NULL );
153
154         *frequency = 48000;
155         *channels = 2;
156         *samples = 1920;
157
158         // Size
159         int size = *samples * *channels * 2;
160
161         // Allocate an image
162         *buffer = malloc( size );
163                 
164         // Read it
165         if ( pipe != NULL )
166                 size = fread( *buffer, size, 1, pipe );
167         else
168                 memset( *buffer, 0, size );
169
170         // Pass the data on the frame properties
171         mlt_frame_set_audio( this, *buffer, *format, size, free );
172
173         return 0;
174 }
175
176 static int read_ppm_header( FILE *video, int *width, int *height )
177 {
178         int count = 0;
179         {
180                 char temp[ 132 ];
181                 char *ignore = fgets( temp, 132, video );
182                 ignore = fgets( temp, 132, video );
183                 count += sscanf( temp, "%d %d", width, height );
184                 ignore = fgets( temp, 132, video );
185         }
186         return count;
187 }
188
189 static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
190 {
191         producer_ppm this = producer->child;
192         int width;
193         int height;
194
195         // Construct a test frame
196         *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
197
198         // Are we at the position expected?
199         producer_ppm_position( this, mlt_producer_frame( producer ) );
200
201         // Get the frames properties
202         mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );
203
204         FILE *video = this->video;
205         FILE *audio = this->audio;
206
207         // Read the video
208         if ( video != NULL && read_ppm_header( video, &width, &height ) == 2 )
209         {
210                 // Allocate an image
211                 uint8_t *image = mlt_pool_alloc( width * ( height + 1 ) * 3 );
212                 
213                 // Read it
214                 size_t ignore;
215                 ignore = fread( image, width * height * 3, 1, video );
216
217                 // Pass the data on the frame properties
218                 mlt_frame_set_image( *frame, image, width * ( height + 1 ) * 3, mlt_pool_release );
219                 mlt_properties_set_int( properties, "width", width );
220                 mlt_properties_set_int( properties, "height", height );
221                 mlt_properties_set_int( properties, "has_image", 1 );
222                 mlt_properties_set_int( properties, "progressive", 1 );
223                 mlt_properties_set_double( properties, "aspect_ratio", 1 );
224
225                 // Push the image callback
226                 mlt_frame_push_get_image( *frame, producer_get_image );
227         }
228         else
229         {
230                 // Push the image callback
231                 mlt_frame_push_get_image( *frame, producer_get_image );
232         }
233
234         // Set the audio pipe
235         mlt_properties_set_data( properties, "audio.pipe", audio, 0, NULL, NULL );
236
237         // Hmm - register audio callback
238         mlt_frame_push_audio( *frame, producer_get_audio );
239
240         // Update timecode on the frame we're creating
241         mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
242
243         // Calculate the next timecode
244         mlt_producer_prepare_next( producer );
245
246         return 0;
247 }
248
249 static void producer_close( mlt_producer parent )
250 {
251         producer_ppm this = parent->child;
252         if ( this->video )
253                 pclose( this->video );
254         if ( this->audio )
255                 pclose( this->audio );
256         free( this->command );
257         parent->close = NULL;
258         mlt_producer_close( parent );
259         free( this );
260 }