]> git.sesse.net Git - mlt/blob - src/modules/vmfx/producer_pgm.c
5a74fa036ec896d450b9ae0f97f41d652102dd5c
[mlt] / src / modules / vmfx / producer_pgm.c
1 /*
2  * producer_pgm.c -- PGM producer
3  * Copyright (C) 2005 Visual Media Fx Inc.
4  * Author: Charles Yates <charles.yates@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * 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 #include <stdlib.h>
24 #include <string.h>
25
26 static int read_pgm( char *name, uint8_t **image, int *width, int *height, int *maxval );
27 static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index );
28 static void producer_close( mlt_producer parent );
29
30 mlt_producer producer_pgm_init( mlt_profile profile, mlt_service_type type, const char *id, char *resource )
31 {
32         mlt_producer this = NULL;
33         uint8_t *image = NULL;
34         int width = 0;
35         int height = 0;
36         int maxval = 0;
37
38         if ( read_pgm( resource, &image, &width, &height, &maxval ) == 0 )
39         {
40                 this = calloc( 1, sizeof( struct mlt_producer_s ) );
41                 if ( this != NULL && mlt_producer_init( this, NULL ) == 0 )
42                 {
43                         mlt_properties properties = MLT_PRODUCER_PROPERTIES( this );
44                         this->get_frame = producer_get_frame;
45                         this->close = ( mlt_destructor )producer_close;
46                         mlt_properties_set( properties, "resource", resource );
47                         mlt_properties_set_data( properties, "image", image, 0, mlt_pool_release, NULL );
48                         mlt_properties_set_int( properties, "meta.media.width", width );
49                         mlt_properties_set_int( properties, "meta.media.height", height );
50                 }
51                 else
52                 {
53                         mlt_pool_release( image );
54                         free( this );
55                         this = NULL;
56                 }
57         }
58
59         return this;
60 }
61
62 /** Load the PGM file.
63 */
64
65 static int read_pgm( char *name, uint8_t **image, int *width, int *height, int *maxval )
66 {
67         uint8_t *input = NULL;
68         int error = 0;
69         FILE *f = fopen( name, "r" );
70         char data[ 512 ];
71
72         // Initialise
73         *image = NULL;
74         *width = 0;
75         *height = 0;
76         *maxval = 0;
77
78         // Get the magic code
79         if ( f != NULL && fgets( data, 511, f ) != NULL && data[ 0 ] == 'P' && data[ 1 ] == '5' )
80         {
81                 char *p = data + 2;
82                 int i = 0;
83                 int val = 0;
84
85                 // PGM Header parser (probably needs to be strengthened)
86                 for ( i = 0; !error && i < 3; i ++ )
87                 {
88                         if ( *p != '\0' && *p != '\n' )
89                                 val = strtol( p, &p, 10 );
90                         else
91                                 p = NULL;
92
93                         while ( error == 0 && p == NULL )
94                         {
95                                 if ( fgets( data, 511, f ) == NULL )
96                                         error = 1;
97                                 else if ( data[ 0 ] != '#' )
98                                         val = strtol( data, &p, 10 );
99                         }
100
101                         switch( i )
102                         {
103                                 case 0: *width = val; break;
104                                 case 1: *height = val; break;
105                                 case 2: *maxval = val; break;
106                         }
107                 }
108                 
109                 if ( !error )
110                 {
111                         // Determine if this is one or two bytes per pixel
112                         int bpp = *maxval > 255 ? 2 : 1;
113                         int size = *width * *height * bpp;
114                         uint8_t *p;
115
116                         // Allocate temporary storage for the data and the image
117                         input = mlt_pool_alloc( *width * *height * bpp );
118                         *image = mlt_pool_alloc( *width * *height * sizeof( uint8_t ) * 2 );
119                         p = *image;
120
121                         error = *image == NULL || input == NULL;
122
123                         if ( !error )
124                         {
125                                 // Read the raw data
126                                 error = fread( input, *width * *height * bpp, 1, f ) != 1;
127
128                                 if ( !error )
129                                 {
130                                         // Convert to yuv422 (very lossy - need to extend this to allow 16 bit alpha out)
131                                         for ( i = 0; i < size; i += bpp )
132                                         {
133                                                 *p ++ = 16 + ( input[ i ] * 219 ) / 255;
134                                                 *p ++ = 128;
135                                         }
136                                 }
137                         }
138                 }
139
140                 if ( error )
141                         mlt_pool_release( *image );
142                 mlt_pool_release( input );
143         }
144         else
145         {
146                 error = 1;
147         }
148
149         if ( f != NULL )
150                 fclose( f );
151
152         return error;
153 }
154
155 static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
156 {
157         mlt_producer producer = mlt_frame_pop_service( this );
158         int real_width = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "meta.media.width" );
159         int real_height = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "meta.media.height" );
160         int size = real_width * real_height;
161         uint8_t *image = mlt_pool_alloc( size * 2 );
162         uint8_t *source = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( producer ), "image", NULL );
163
164         mlt_frame_set_image( this, image, size * 2, mlt_pool_release );
165
166         *width = real_width;
167         *height = real_height;
168         *format = mlt_image_yuv422;
169         *buffer = image;
170
171         if ( image != NULL && source != NULL )
172                 memcpy( image, source, size * 2 );
173
174         return 0;
175 }
176
177 static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
178 {
179         // Construct a test frame
180         *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
181
182         // Get the frames properties
183         mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );
184
185         // Pass the data on the frame properties
186         mlt_properties_set_int( properties, "has_image", 1 );
187         mlt_properties_set_int( properties, "progressive", 1 );
188         mlt_properties_set_double( properties, "aspect_ratio", 1 );
189
190         // Push the image callback
191         mlt_frame_push_service( *frame, producer );
192         mlt_frame_push_get_image( *frame, producer_get_image );
193
194         // Update timecode on the frame we're creating
195         mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
196
197         // Calculate the next timecode
198         mlt_producer_prepare_next( producer );
199
200         return 0;
201 }
202
203 static void producer_close( mlt_producer parent )
204 {
205         parent->close = NULL;
206         mlt_producer_close( parent );
207         free( parent );
208 }