Statistics
| Branch: | Revision:

ffmpeg / vhook / ppm.c @ 25e4f8aa

History | View | Annotate | Download (9.33 KB)

1 bee0d9e5 Charles Yates
/*
2 115329f1 Diego Biurrun
 * PPM Video Hook
3 bee0d9e5 Charles Yates
 * Copyright (c) 2003 Charles Yates
4
 *
5 b78e7197 Diego Biurrun
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8 bee0d9e5 Charles Yates
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10 b78e7197 Diego Biurrun
 * version 2.1 of the License, or (at your option) any later version.
11 bee0d9e5 Charles Yates
 *
12 b78e7197 Diego Biurrun
 * FFmpeg is distributed in the hope that it will be useful,
13 bee0d9e5 Charles Yates
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18 b78e7197 Diego Biurrun
 * License along with FFmpeg; if not, write to the Free Software
19 5509bffa Diego Biurrun
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 bee0d9e5 Charles Yates
 */
21
22
#include <stdio.h>
23
#include <unistd.h>
24
#include <fcntl.h>
25
#include <sys/types.h>
26
#include <sys/wait.h>
27
#include <ctype.h>
28
#include "framehook.h"
29 cf344ec7 François Revol
#include "avformat.h"
30 a4dd5fb7 Víctor Paesa
#include "swscale.h"
31
32
static int sws_flags = SWS_BICUBIC;
33 bee0d9e5 Charles Yates
34
/** Bi-directional pipe structure.
35
*/
36
37
typedef struct rwpipe
38
{
39 1e4ddde2 Charles Yates
    int pid;
40
    FILE *reader;
41
    FILE *writer;
42 bee0d9e5 Charles Yates
}
43
rwpipe;
44
45
/** Create a bidirectional pipe for the given command.
46
*/
47
48 ceaf1909 Dieter
static rwpipe *rwpipe_open( int argc, char *argv[] )
49 bee0d9e5 Charles Yates
{
50 1e4ddde2 Charles Yates
    rwpipe *this = av_mallocz( sizeof( rwpipe ) );
51 bee0d9e5 Charles Yates
52 1e4ddde2 Charles Yates
    if ( this != NULL )
53
    {
54 bee0d9e5 Charles Yates
        int input[ 2 ];
55
        int output[ 2 ];
56
57
        pipe( input );
58
        pipe( output );
59
60
        this->pid = fork();
61
62
        if ( this->pid == 0 )
63
        {
64 1f3f9507 Michael Niedermayer
#define COMMAND_SIZE 10240
65
            char *command = av_mallocz( COMMAND_SIZE );
66 1e4ddde2 Charles Yates
            int i;
67 bee0d9e5 Charles Yates
68 1e4ddde2 Charles Yates
            strcpy( command, "" );
69
            for ( i = 0; i < argc; i ++ )
70
            {
71 1f3f9507 Michael Niedermayer
                pstrcat( command, COMMAND_SIZE, argv[ i ] );
72
                pstrcat( command, COMMAND_SIZE, " " );
73 1e4ddde2 Charles Yates
            }
74 bee0d9e5 Charles Yates
75
            dup2( output[ 0 ], STDIN_FILENO );
76
            dup2( input[ 1 ], STDOUT_FILENO );
77
78
            close( input[ 0 ] );
79
            close( input[ 1 ] );
80
            close( output[ 0 ] );
81
            close( output[ 1 ] );
82
83 efe41983 Michael Niedermayer
            execl("/bin/sh", "sh", "-c", command, (char*)NULL );
84 f321635a Víctor Paesa
            _exit( 255 );
85 bee0d9e5 Charles Yates
        }
86
        else
87
        {
88
            close( input[ 1 ] );
89
            close( output[ 0 ] );
90
91
            this->reader = fdopen( input[ 0 ], "r" );
92
            this->writer = fdopen( output[ 1 ], "w" );
93
        }
94 1e4ddde2 Charles Yates
    }
95 bee0d9e5 Charles Yates
96 1e4ddde2 Charles Yates
    return this;
97 bee0d9e5 Charles Yates
}
98
99
/** Read data from the pipe.
100
*/
101
102 ceaf1909 Dieter
static FILE *rwpipe_reader( rwpipe *this )
103 bee0d9e5 Charles Yates
{
104 1e4ddde2 Charles Yates
    if ( this != NULL )
105
        return this->reader;
106
    else
107
        return NULL;
108 bee0d9e5 Charles Yates
}
109
110
/** Write data to the pipe.
111
*/
112
113 ceaf1909 Dieter
static FILE *rwpipe_writer( rwpipe *this )
114 bee0d9e5 Charles Yates
{
115 1e4ddde2 Charles Yates
    if ( this != NULL )
116
        return this->writer;
117
    else
118
        return NULL;
119
}
120
121
/* Read a number from the pipe - assumes PNM style headers.
122
*/
123
124 ceaf1909 Dieter
static int rwpipe_read_number( rwpipe *rw )
125 1e4ddde2 Charles Yates
{
126
    int value = 0;
127
    int c = 0;
128
    FILE *in = rwpipe_reader( rw );
129
130 115329f1 Diego Biurrun
    do
131 1e4ddde2 Charles Yates
    {
132
        c = fgetc( in );
133
134
        while( c != EOF && !isdigit( c ) && c != '#' )
135
            c = fgetc( in );
136
137
        if ( c == '#' )
138
            while( c != EOF && c != '\n' )
139
                c = fgetc( in );
140
    }
141
    while ( c != EOF && !isdigit( c ) );
142
143
    while( c != EOF && isdigit( c ) )
144
    {
145
        value = value * 10 + ( c - '0' );
146
        c = fgetc( in );
147
    }
148
149
    return value;
150
}
151
152
/** Read a PPM P6 header.
153
*/
154
155 ceaf1909 Dieter
static int rwpipe_read_ppm_header( rwpipe *rw, int *width, int *height )
156 1e4ddde2 Charles Yates
{
157
    char line[ 3 ];
158
    FILE *in = rwpipe_reader( rw );
159
    int max;
160
161
    fgets( line, 3, in );
162
    if ( !strncmp( line, "P6", 2 ) )
163
    {
164
        *width = rwpipe_read_number( rw );
165
        *height = rwpipe_read_number( rw );
166
        max = rwpipe_read_number( rw );
167
        return max != 255 || *width <= 0 || *height <= 0;
168
    }
169
    return 1;
170 bee0d9e5 Charles Yates
}
171
172
/** Close the pipe and process.
173
*/
174
175 ceaf1909 Dieter
static void rwpipe_close( rwpipe *this )
176 bee0d9e5 Charles Yates
{
177 1e4ddde2 Charles Yates
    if ( this != NULL )
178
    {
179
        fclose( this->reader );
180
        fclose( this->writer );
181
        waitpid( this->pid, NULL, 0 );
182
        av_free( this );
183
    }
184 bee0d9e5 Charles Yates
}
185
186 1e4ddde2 Charles Yates
/** Context info for this vhook - stores the pipe and image buffers.
187
*/
188
189 115329f1 Diego Biurrun
typedef struct
190 bee0d9e5 Charles Yates
{
191 1e4ddde2 Charles Yates
    rwpipe *rw;
192
    int size1;
193
    char *buf1;
194
    int size2;
195
    char *buf2;
196 a4dd5fb7 Víctor Paesa
197
    // This vhook first converts frame to RGB ...
198
    struct SwsContext *toRGB_convert_ctx;
199
    // ... then processes it via a PPM command pipe ...
200
    // ... and finally converts back frame from RGB to initial format
201
    struct SwsContext *fromRGB_convert_ctx;
202 115329f1 Diego Biurrun
}
203 bee0d9e5 Charles Yates
ContextInfo;
204
205 1e4ddde2 Charles Yates
/** Initialise the context info for this vhook.
206
*/
207 bee0d9e5 Charles Yates
208 1e4ddde2 Charles Yates
int Configure(void **ctxp, int argc, char *argv[])
209 bee0d9e5 Charles Yates
{
210 1e4ddde2 Charles Yates
    if ( argc > 1 )
211
    {
212
        *ctxp = av_mallocz(sizeof(ContextInfo));
213
        if ( ctxp != NULL && argc > 1 )
214
        {
215
            ContextInfo *info = (ContextInfo *)*ctxp;
216
            info->rw = rwpipe_open( argc - 1, &argv[ 1 ] );
217
            return 0;
218
        }
219
    }
220
    return 1;
221 bee0d9e5 Charles Yates
}
222
223 1e4ddde2 Charles Yates
/** Process a frame.
224
*/
225 bee0d9e5 Charles Yates
226
void Process(void *ctx, AVPicture *picture, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
227
{
228 1e4ddde2 Charles Yates
    int err = 0;
229 bee0d9e5 Charles Yates
    ContextInfo *ci = (ContextInfo *) ctx;
230
    AVPicture picture1;
231
    AVPicture picture2;
232
    AVPicture *pict = picture;
233 1e4ddde2 Charles Yates
    int out_width;
234
    int out_height;
235
    int i;
236
    uint8_t *ptr = NULL;
237
    FILE *in = rwpipe_reader( ci->rw );
238
    FILE *out = rwpipe_writer( ci->rw );
239
240
    /* Check that we have a pipe to talk to. */
241
    if ( in == NULL || out == NULL )
242
        err = 1;
243
244
    /* Convert to RGB24 if necessary */
245 115329f1 Diego Biurrun
    if ( !err && pix_fmt != PIX_FMT_RGB24 )
246 1e4ddde2 Charles Yates
    {
247
        int size = avpicture_get_size(PIX_FMT_RGB24, width, height);
248
249
        if ( size != ci->size1 )
250
        {
251
            av_free( ci->buf1 );
252
            ci->buf1 = av_malloc(size);
253
            ci->size1 = size;
254
            err = ci->buf1 == NULL;
255
        }
256
257
        if ( !err )
258
        {
259
            avpicture_fill(&picture1, ci->buf1, PIX_FMT_RGB24, width, height);
260 a4dd5fb7 Víctor Paesa
261
            // if we already got a SWS context, let's realloc if is not re-useable
262
            ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
263
                                        width, height, pix_fmt,
264
                                        width, height, PIX_FMT_RGB24,
265
                                        sws_flags, NULL, NULL, NULL);
266
            if (ci->toRGB_convert_ctx == NULL) {
267
                av_log(NULL, AV_LOG_ERROR,
268
                       "Cannot initialize the toRGB conversion context\n");
269 ca345e44 Diego Biurrun
                return;
270 a4dd5fb7 Víctor Paesa
            }
271
272
// img_convert parameters are          2 first destination, then 4 source
273
// sws_scale   parameters are context, 4 first source,      then 2 destination
274
            sws_scale(ci->toRGB_convert_ctx,
275
                     picture->data, picture->linesize, 0, height,
276
                     picture1.data, picture1.linesize);
277
278 1e4ddde2 Charles Yates
            pict = &picture1;
279
        }
280
    }
281
282
    /* Write out the PPM */
283
    if ( !err )
284
    {
285
        ptr = pict->data[ 0 ];
286
        fprintf( out, "P6\n%d %d\n255\n", width, height );
287
        for ( i = 0; !err && i < height; i ++ )
288
        {
289
            err = !fwrite( ptr, width * 3, 1, out );
290
            ptr += pict->linesize[ 0 ];
291 bee0d9e5 Charles Yates
        }
292 1e4ddde2 Charles Yates
        if ( !err )
293
            err = fflush( out );
294 bee0d9e5 Charles Yates
    }
295
296 1e4ddde2 Charles Yates
    /* Read the PPM returned. */
297
    if ( !err && !rwpipe_read_ppm_header( ci->rw, &out_width, &out_height ) )
298
    {
299 bee0d9e5 Charles Yates
        int size = avpicture_get_size(PIX_FMT_RGB24, out_width, out_height);
300 1e4ddde2 Charles Yates
301
        if ( size != ci->size2 )
302
        {
303
            av_free( ci->buf2 );
304
            ci->buf2 = av_malloc(size);
305
            ci->size2 = size;
306
            err = ci->buf2 == NULL;
307
        }
308
309
        if ( !err )
310
        {
311
            avpicture_fill(&picture2, ci->buf2, PIX_FMT_RGB24, out_width, out_height);
312
            ptr = picture2.data[ 0 ];
313
            for ( i = 0; !err && i < out_height; i ++ )
314
            {
315
                err = !fread( ptr, out_width * 3, 1, in );
316
                ptr += picture2.linesize[ 0 ];
317
            }
318 bee0d9e5 Charles Yates
        }
319 1e4ddde2 Charles Yates
    }
320 bee0d9e5 Charles Yates
321 1e4ddde2 Charles Yates
    /* Convert the returned PPM back to the input format */
322
    if ( !err )
323
    {
324 a4dd5fb7 Víctor Paesa
        /* The out_width/out_height returned from the PPM
325
         * filter won't necessarily be the same as width and height
326
         * but it will be scaled anyway to width/height.
327 1e4ddde2 Charles Yates
         */
328 a4dd5fb7 Víctor Paesa
        av_log(NULL, AV_LOG_DEBUG,
329
                  "PPM vhook: Input dimensions: %d x %d Output dimensions: %d x %d\n",
330
                  width, height, out_width, out_height);
331
        ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
332
                                        out_width, out_height, PIX_FMT_RGB24,
333
                                        width,     height,     pix_fmt,
334
                                        sws_flags, NULL, NULL, NULL);
335
        if (ci->fromRGB_convert_ctx == NULL) {
336
            av_log(NULL, AV_LOG_ERROR,
337
                   "Cannot initialize the fromRGB conversion context\n");
338 ca345e44 Diego Biurrun
            return;
339 1e4ddde2 Charles Yates
        }
340 a4dd5fb7 Víctor Paesa
341
// img_convert parameters are          2 first destination, then 4 source
342
// sws_scale   parameters are context, 4 first source,      then 2 destination
343
        sws_scale(ci->fromRGB_convert_ctx,
344
                 picture2.data, picture2.linesize, 0, out_height,
345
                 picture->data, picture->linesize);
346 1e4ddde2 Charles Yates
    }
347 bee0d9e5 Charles Yates
}
348
349 1e4ddde2 Charles Yates
/** Clean up the effect.
350
*/
351
352 bee0d9e5 Charles Yates
void Release(void *ctx)
353
{
354
    ContextInfo *ci;
355
    ci = (ContextInfo *) ctx;
356
357
    if (ctx)
358 1e4ddde2 Charles Yates
    {
359
        rwpipe_close( ci->rw );
360
        av_free( ci->buf1 );
361
        av_free( ci->buf2 );
362 a4dd5fb7 Víctor Paesa
        sws_freeContext(ci->toRGB_convert_ctx);
363
        sws_freeContext(ci->fromRGB_convert_ctx);
364 bee0d9e5 Charles Yates
        av_free(ctx);
365 1e4ddde2 Charles Yates
    }
366 bee0d9e5 Charles Yates
}