Statistics
| Branch: | Revision:

ffmpeg / vhook / watermark.c @ 71e445fc

History | View | Annotate | Download (22.9 KB)

1 21754ce6 Michael Niedermayer
/*
2 115329f1 Diego Biurrun
 * Watermark Hook
3 21754ce6 Michael Niedermayer
 * Copyright (c) 2005 Marcus Engene myfirstname(at)mylastname.se
4
 *
5 8dfcf67e Diego Biurrun
 * parameters for watermark:
6 ed818e25 Marcus Engene
 *  -m nbr = nbr is 0..1. 0 is the default mode, see below.
7
 *  -t nbr = nbr is six digit hex. Threshold.
8 8dfcf67e Diego Biurrun
 *  -f file = file is the watermark image filename. You must specify this!
9 ed818e25 Marcus Engene
 *
10
 * MODE 0:
11 8dfcf67e Diego Biurrun
 * The watermark picture works like this (assuming color intensities 0..0xff):
12 21754ce6 Michael Niedermayer
 * Per color do this:
13 8dfcf67e Diego Biurrun
 * If mask color is 0x80, no change to the original frame.
14
 * If mask color is < 0x80 the abs difference is subtracted from the frame. If
15 21754ce6 Michael Niedermayer
 * result < 0, result = 0
16 8dfcf67e Diego Biurrun
 * If mask color is > 0x80 the abs difference is added to the frame. If result
17 21754ce6 Michael Niedermayer
 * > 0xff, result = 0xff
18
 *
19 8dfcf67e Diego Biurrun
 * You can override the 0x80 level with the -t flag. E.g. if threshold is
20
 * 000000 the color value of watermark is added to the destination.
21 ed818e25 Marcus Engene
 *
22 21754ce6 Michael Niedermayer
 * This way a mask that is visible both in light pictures and in dark can be
23 8dfcf67e Diego Biurrun
 * made (fex by using a picture generated by Gimp and the bump map tool).
24 21754ce6 Michael Niedermayer
 *
25
 * An example watermark file is at
26
 * http://engene.se/ffmpeg_watermark.gif
27
 *
28 ed818e25 Marcus Engene
 * MODE 1:
29
 * Per color do this:
30 8dfcf67e Diego Biurrun
 * If mask color > threshold color then the watermark pixel is used.
31 ed818e25 Marcus Engene
 *
32 ded78ac0 Marcus Engene
 * Example usage:
33 ed818e25 Marcus Engene
 *  ffmpeg -i infile -vhook '/path/watermark.so -f wm.gif' -an out.mov
34
 *  ffmpeg -i infile -vhook '/path/watermark.so -f wm.gif -m 1 -t 222222' -an out.mov
35 ded78ac0 Marcus Engene
 *
36
 * Note that the entire vhook argument is encapsulated in ''. This
37 8dfcf67e Diego Biurrun
 * way, arguments to the vhook won't be mixed up with those for ffmpeg.
38 ded78ac0 Marcus Engene
 *
39 b78e7197 Diego Biurrun
 * This file is part of FFmpeg.
40
 *
41
 * FFmpeg is free software; you can redistribute it and/or
42 21754ce6 Michael Niedermayer
 * modify it under the terms of the GNU Lesser General Public
43
 * License as published by the Free Software Foundation; either
44 b78e7197 Diego Biurrun
 * version 2.1 of the License, or (at your option) any later version.
45 21754ce6 Michael Niedermayer
 *
46 b78e7197 Diego Biurrun
 * FFmpeg is distributed in the hope that it will be useful,
47 21754ce6 Michael Niedermayer
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
48
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
49
 * Lesser General Public License for more details.
50
 *
51
 * You should have received a copy of the GNU Lesser General Public
52 b78e7197 Diego Biurrun
 * License along with FFmpeg; if not, write to the Free Software
53 5509bffa Diego Biurrun
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
54 21754ce6 Michael Niedermayer
 */
55
56 ed818e25 Marcus Engene
#include <stdlib.h>
57 21754ce6 Michael Niedermayer
//#include <fcntl.h>
58
#include <unistd.h>
59
#include <stdarg.h>
60 115329f1 Diego Biurrun
61 21754ce6 Michael Niedermayer
#include "common.h"
62
#include "avformat.h"
63
64
#include "framehook.h"
65 a851b8e8 Dieter
#include "cmdutils.h"
66 2d7490fc Víctor Paesa
#include "swscale.h"
67
68
static int sws_flags = SWS_BICUBIC;
69 21754ce6 Michael Niedermayer
70
typedef struct {
71
    char            filename[2000];
72
    int             x_size;
73
    int             y_size;
74
75
    /* get_watermark_picture() variables */
76
    AVFormatContext *pFormatCtx;
77
    const char     *p_ext;
78
    int             videoStream;
79
    int             frameFinished;
80 115329f1 Diego Biurrun
    AVCodecContext *pCodecCtx;
81
    AVCodec        *pCodec;
82 21754ce6 Michael Niedermayer
    AVFrame        *pFrame;
83
    AVPacket        packet;
84
    int             numBytes;
85
    uint8_t        *buffer;
86
    int             i;
87
    AVInputFormat  *file_iformat;
88
    AVStream       *st;
89 115329f1 Diego Biurrun
    int             is_done;
90 21754ce6 Michael Niedermayer
    AVFrame        *pFrameRGB;
91 ed818e25 Marcus Engene
    int             thrR;
92
    int             thrG;
93
    int             thrB;
94
    int             mode;
95 2d7490fc Víctor Paesa
96
    // This vhook first converts frame to RGB ...
97
    struct SwsContext *toRGB_convert_ctx;
98
    // ... then converts a watermark and applies it to the RGB frame ...
99
    struct SwsContext *watermark_convert_ctx;
100
    // ... and finally converts back frame from RGB to initial format
101
    struct SwsContext *fromRGB_convert_ctx;
102 21754ce6 Michael Niedermayer
} ContextInfo;
103
104
int get_watermark_picture(ContextInfo *ci, int cleanup);
105
106
107
/****************************************************************************
108 115329f1 Diego Biurrun
 *
109 21754ce6 Michael Niedermayer
 ****************************************************************************/
110
void Release(void *ctx)
111
{
112
    ContextInfo *ci;
113
    ci = (ContextInfo *) ctx;
114
115 2d7490fc Víctor Paesa
    if (ci) {
116
        get_watermark_picture(ci, 1);
117
        sws_freeContext(ci->toRGB_convert_ctx);
118
        sws_freeContext(ci->watermark_convert_ctx);
119
        sws_freeContext(ci->fromRGB_convert_ctx);
120
    }
121 b4902c11 Michael Niedermayer
    av_free(ctx);
122 21754ce6 Michael Niedermayer
}
123
124
125
/****************************************************************************
126 115329f1 Diego Biurrun
 *
127 21754ce6 Michael Niedermayer
 ****************************************************************************/
128
int Configure(void **ctxp, int argc, char *argv[])
129
{
130
    ContextInfo *ci;
131
    int c;
132 ed818e25 Marcus Engene
    int tmp = 0;
133 21754ce6 Michael Niedermayer
134
    if (0 == (*ctxp = av_mallocz(sizeof(ContextInfo)))) return -1;
135
    ci = (ContextInfo *) *ctxp;
136
137 f368375c Marcus Engene
    optind = 1;
138 115329f1 Diego Biurrun
139 21754ce6 Michael Niedermayer
    // Struct is mallocz:ed so no need to reset.
140 ed818e25 Marcus Engene
    ci->thrR = 0x80;
141
    ci->thrG = 0x80;
142
    ci->thrB = 0x80;
143 115329f1 Diego Biurrun
144 ed818e25 Marcus Engene
    while ((c = getopt(argc, argv, "f:m:t:")) > 0) {
145 21754ce6 Michael Niedermayer
        switch (c) {
146
            case 'f':
147
                strncpy(ci->filename, optarg, 1999);
148
                ci->filename[1999] = 0;
149
                break;
150 ed818e25 Marcus Engene
            case 'm':
151
                ci->mode = atoi(optarg);
152
                break;
153
            case 't':
154
                if (1 != sscanf(optarg, "%x", &tmp)) {
155
                    av_log(NULL, AV_LOG_ERROR, "Watermark: argument to -t must be a 6 digit hex number\n");
156
                    return -1;
157
                }
158
                ci->thrR = (tmp >> 16) & 0xff;
159
                ci->thrG = (tmp >> 8) & 0xff;
160
                ci->thrB = (tmp >> 0) & 0xff;
161
                break;
162 21754ce6 Michael Niedermayer
            default:
163 f368375c Marcus Engene
                av_log(NULL, AV_LOG_ERROR, "Watermark: Unrecognized argument '%s'\n", argv[optind]);
164 21754ce6 Michael Niedermayer
                return -1;
165
        }
166
    }
167 115329f1 Diego Biurrun
168 21754ce6 Michael Niedermayer
    //
169 f368375c Marcus Engene
    if (0 == ci->filename[0]) {
170
        av_log(NULL, AV_LOG_ERROR, "Watermark: There is no filename specified.\n");
171
        return -1;
172
    }
173 115329f1 Diego Biurrun
174 21754ce6 Michael Niedermayer
    av_register_all();
175
    return get_watermark_picture(ci, 0);
176
}
177
178
179
/****************************************************************************
180 ed818e25 Marcus Engene
 * For mode 0 (the original one)
181 21754ce6 Michael Niedermayer
 ****************************************************************************/
182 7b49ce2e Stefan Huehner
static void Process0(void *ctx,
183 ed818e25 Marcus Engene
              AVPicture *picture,
184
              enum PixelFormat pix_fmt,
185
              int src_width,
186
              int src_height,
187
              int64_t pts)
188 21754ce6 Michael Niedermayer
{
189
    ContextInfo *ci = (ContextInfo *) ctx;
190
    char *buf = 0;
191
    AVPicture picture1;
192
    AVPicture *pict = picture;
193 115329f1 Diego Biurrun
194 21754ce6 Michael Niedermayer
    AVFrame *pFrameRGB;
195
    int xm_size;
196
    int ym_size;
197
198
    int x;
199
    int y;
200
    int offs, offsm;
201
    int mpoffs;
202
    uint32_t *p_pixel = 0;
203
    uint32_t pixel_meck;
204
    uint32_t pixel;
205
    uint32_t pixelm;
206 115329f1 Diego Biurrun
    int tmp;
207 ed818e25 Marcus Engene
    int thrR = ci->thrR;
208
    int thrG = ci->thrG;
209
    int thrB = ci->thrB;
210 21754ce6 Michael Niedermayer
211 71e445fc Diego Biurrun
    if (pix_fmt != PIX_FMT_RGB32) {
212 21754ce6 Michael Niedermayer
        int size;
213
214 71e445fc Diego Biurrun
        size = avpicture_get_size(PIX_FMT_RGB32, src_width, src_height);
215 21754ce6 Michael Niedermayer
        buf = av_malloc(size);
216
217 71e445fc Diego Biurrun
        avpicture_fill(&picture1, buf, PIX_FMT_RGB32, src_width, src_height);
218 2d7490fc Víctor Paesa
219
        // if we already got a SWS context, let's realloc if is not re-useable
220
        ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
221
                                    src_width, src_height, pix_fmt,
222 71e445fc Diego Biurrun
                                    src_width, src_height, PIX_FMT_RGB32,
223 2d7490fc Víctor Paesa
                                    sws_flags, NULL, NULL, NULL);
224
        if (ci->toRGB_convert_ctx == NULL) {
225
            av_log(NULL, AV_LOG_ERROR,
226
                   "Cannot initialize the toRGB conversion context\n");
227
            exit(1);
228 21754ce6 Michael Niedermayer
        }
229 2d7490fc Víctor Paesa
230
// img_convert parameters are          2 first destination, then 4 source
231
// sws_scale   parameters are context, 4 first source,      then 2 destination
232
        sws_scale(ci->toRGB_convert_ctx,
233
                 picture->data, picture->linesize, 0, src_height,
234
                 picture1.data, picture1.linesize);
235
236 21754ce6 Michael Niedermayer
        pict = &picture1;
237
    }
238
239
    /* Insert filter code here */ /* ok */
240
241 115329f1 Diego Biurrun
    // Get me next frame
242 21754ce6 Michael Niedermayer
    if (0 > get_watermark_picture(ci, 0)) {
243
        return;
244 115329f1 Diego Biurrun
    }
245 21754ce6 Michael Niedermayer
    // These are the three original static variables in the ffmpeg hack.
246
    pFrameRGB = ci->pFrameRGB;
247
    xm_size = ci->x_size;
248
    ym_size = ci->y_size;
249 115329f1 Diego Biurrun
250 21754ce6 Michael Niedermayer
    // I'll do the *4 => <<2 crap later. Most compilers understand that anyway.
251 71e445fc Diego Biurrun
    // According to avcodec.h PIX_FMT_RGB32 is handled in endian specific manner.
252 21754ce6 Michael Niedermayer
    for (y=0; y<src_height; y++) {
253
        offs = y * (src_width * 4);
254
        offsm = (((y * ym_size) / src_height) * 4) * xm_size; // offsm first in maskline. byteoffs!
255
        for (x=0; x<src_width; x++) {
256
            mpoffs = offsm + (((x * xm_size) / src_width) * 4);
257
            p_pixel = (uint32_t *)&((pFrameRGB->data[0])[mpoffs]);
258
            pixelm = *p_pixel;
259
            p_pixel = (uint32_t *)&((pict->data[0])[offs]);
260
            pixel = *p_pixel;
261
//          pixelm = *((uint32_t *)&(pFrameRGB->data[mpoffs]));
262
            pixel_meck = pixel & 0xff000000;
263
264
            // R
265 ed818e25 Marcus Engene
            tmp = (int)((pixel >> 16) & 0xff) + (int)((pixelm >> 16) & 0xff) - thrR;
266 21754ce6 Michael Niedermayer
            if (tmp > 255) tmp = 255;
267
            if (tmp < 0) tmp = 0;
268
            pixel_meck |= (tmp << 16) & 0xff0000;
269
            // G
270 ed818e25 Marcus Engene
            tmp = (int)((pixel >> 8) & 0xff) + (int)((pixelm >> 8) & 0xff) - thrG;
271 21754ce6 Michael Niedermayer
            if (tmp > 255) tmp = 255;
272
            if (tmp < 0) tmp = 0;
273
            pixel_meck |= (tmp << 8) & 0xff00;
274
            // B
275 ed818e25 Marcus Engene
            tmp = (int)((pixel >> 0) & 0xff) + (int)((pixelm >> 0) & 0xff) - thrB;
276 21754ce6 Michael Niedermayer
            if (tmp > 255) tmp = 255;
277
            if (tmp < 0) tmp = 0;
278
            pixel_meck |= (tmp << 0) & 0xff;
279 115329f1 Diego Biurrun
280
281 21754ce6 Michael Niedermayer
            // test:
282
            //pixel_meck = pixel & 0xff000000;
283
            //pixel_meck |= (pixelm & 0x00ffffff);
284
285
            *p_pixel = pixel_meck;
286
287 115329f1 Diego Biurrun
            offs += 4;
288 21754ce6 Michael Niedermayer
        } // foreach X
289 115329f1 Diego Biurrun
    } // foreach Y
290
291
292
293 21754ce6 Michael Niedermayer
294 71e445fc Diego Biurrun
    if (pix_fmt != PIX_FMT_RGB32) {
295 2d7490fc Víctor Paesa
        ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
296 71e445fc Diego Biurrun
                                      src_width, src_height, PIX_FMT_RGB32,
297 2d7490fc Víctor Paesa
                                      src_width, src_height, pix_fmt,
298
                                      sws_flags, NULL, NULL, NULL);
299
        if (ci->fromRGB_convert_ctx == NULL) {
300
            av_log(NULL, AV_LOG_ERROR,
301
                   "Cannot initialize the fromRGB conversion context\n");
302
            exit(1);
303 21754ce6 Michael Niedermayer
        }
304 2d7490fc Víctor Paesa
// img_convert parameters are          2 first destination, then 4 source
305
// sws_scale   parameters are context, 4 first source,      then 2 destination
306
        sws_scale(ci->fromRGB_convert_ctx,
307
                 picture1.data, picture1.linesize, 0, src_height,
308
                 picture->data, picture->linesize);
309 21754ce6 Michael Niedermayer
    }
310
311
    av_free(buf);
312
}
313
314
315
/****************************************************************************
316 ed818e25 Marcus Engene
 * For mode 1 (the original one)
317
 ****************************************************************************/
318 7b49ce2e Stefan Huehner
static void Process1(void *ctx,
319 ed818e25 Marcus Engene
              AVPicture *picture,
320
              enum PixelFormat pix_fmt,
321
              int src_width,
322
              int src_height,
323
              int64_t pts)
324
{
325
    ContextInfo *ci = (ContextInfo *) ctx;
326
    char *buf = 0;
327
    AVPicture picture1;
328
    AVPicture *pict = picture;
329
330
    AVFrame *pFrameRGB;
331
    int xm_size;
332
    int ym_size;
333
334
    int x;
335
    int y;
336
    int offs, offsm;
337
    int mpoffs;
338
    uint32_t *p_pixel = 0;
339
    uint32_t pixel;
340
    uint32_t pixelm;
341
342 71e445fc Diego Biurrun
    if (pix_fmt != PIX_FMT_RGB32) {
343 ed818e25 Marcus Engene
        int size;
344
345 71e445fc Diego Biurrun
        size = avpicture_get_size(PIX_FMT_RGB32, src_width, src_height);
346 ed818e25 Marcus Engene
        buf = av_malloc(size);
347
348 71e445fc Diego Biurrun
        avpicture_fill(&picture1, buf, PIX_FMT_RGB32, src_width, src_height);
349 2d7490fc Víctor Paesa
350
        // if we already got a SWS context, let's realloc if is not re-useable
351
        ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
352
                                    src_width, src_height, pix_fmt,
353 71e445fc Diego Biurrun
                                    src_width, src_height, PIX_FMT_RGB32,
354 2d7490fc Víctor Paesa
                                    sws_flags, NULL, NULL, NULL);
355
        if (ci->toRGB_convert_ctx == NULL) {
356
            av_log(NULL, AV_LOG_ERROR,
357
                   "Cannot initialize the toRGB conversion context\n");
358
            exit(1);
359 ed818e25 Marcus Engene
        }
360 2d7490fc Víctor Paesa
361
// img_convert parameters are          2 first destination, then 4 source
362
// sws_scale   parameters are context, 4 first source,      then 2 destination
363
        sws_scale(ci->toRGB_convert_ctx,
364
                 picture->data, picture->linesize, 0, src_height,
365
                 picture1.data, picture1.linesize);
366
367 ed818e25 Marcus Engene
        pict = &picture1;
368
    }
369
370
    /* Insert filter code here */ /* ok */
371
372
    // Get me next frame
373
    if (0 > get_watermark_picture(ci, 0)) {
374
        return;
375
    }
376
    // These are the three original static variables in the ffmpeg hack.
377
    pFrameRGB = ci->pFrameRGB;
378
    xm_size = ci->x_size;
379
    ym_size = ci->y_size;
380
381
    // I'll do the *4 => <<2 crap later. Most compilers understand that anyway.
382 71e445fc Diego Biurrun
    // According to avcodec.h PIX_FMT_RGB32 is handled in endian specific manner.
383 ed818e25 Marcus Engene
    for (y=0; y<src_height; y++) {
384
        offs = y * (src_width * 4);
385
        offsm = (((y * ym_size) / src_height) * 4) * xm_size; // offsm first in maskline. byteoffs!
386
        for (x=0; x<src_width; x++) {
387
            mpoffs = offsm + (((x * xm_size) / src_width) * 4);
388
            p_pixel = (uint32_t *)&((pFrameRGB->data[0])[mpoffs]);
389
            pixelm = *p_pixel; /* watermark pixel */
390
            p_pixel = (uint32_t *)&((pict->data[0])[offs]);
391
            pixel = *p_pixel;
392
393
            if (((pixelm >> 16) & 0xff) > ci->thrR ||
394
                ((pixelm >>  8) & 0xff) > ci->thrG ||
395
                ((pixelm >>  0) & 0xff) > ci->thrB)
396
            {
397
                *p_pixel = pixelm;
398
            } else {
399
                *p_pixel = pixel;
400
            }
401
            offs += 4;
402
        } // foreach X
403
    } // foreach Y
404
405 71e445fc Diego Biurrun
    if (pix_fmt != PIX_FMT_RGB32) {
406 2d7490fc Víctor Paesa
        ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
407 71e445fc Diego Biurrun
                                      src_width, src_height, PIX_FMT_RGB32,
408 2d7490fc Víctor Paesa
                                      src_width, src_height, pix_fmt,
409
                                      sws_flags, NULL, NULL, NULL);
410
        if (ci->fromRGB_convert_ctx == NULL) {
411
            av_log(NULL, AV_LOG_ERROR,
412
                   "Cannot initialize the fromRGB conversion context\n");
413
            exit(1);
414 ed818e25 Marcus Engene
        }
415 2d7490fc Víctor Paesa
// img_convert parameters are          2 first destination, then 4 source
416
// sws_scale   parameters are context, 4 first source,      then 2 destination
417
        sws_scale(ci->fromRGB_convert_ctx,
418
                 picture1.data, picture1.linesize, 0, src_height,
419
                 picture->data, picture->linesize);
420 ed818e25 Marcus Engene
    }
421
422
    av_free(buf);
423
}
424
425
426
/****************************************************************************
427
 * This is the function ffmpeg.c callbacks.
428
 ****************************************************************************/
429
void Process(void *ctx,
430
             AVPicture *picture,
431
             enum PixelFormat pix_fmt,
432
             int src_width,
433
             int src_height,
434
             int64_t pts)
435
{
436
    ContextInfo *ci = (ContextInfo *) ctx;
437
    if (1 == ci->mode) {
438
        return Process1(ctx, picture, pix_fmt, src_width, src_height, pts);
439
    } else {
440
        return Process0(ctx, picture, pix_fmt, src_width, src_height, pts);
441
    }
442
}
443
444
445
/****************************************************************************
446 21754ce6 Michael Niedermayer
 * When cleanup == 0, we try to get the next frame. If no next frame, nothing
447
 * is done.
448
 *
449 115329f1 Diego Biurrun
 * This code follows the example on
450 21754ce6 Michael Niedermayer
 * http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html
451
 *
452
 * 0 = ok, -1 = error
453
 ****************************************************************************/
454
int get_watermark_picture(ContextInfo *ci, int cleanup)
455
{
456
    if (1 == ci->is_done && 0 == cleanup) return 0;
457
458
    // Yes, *pFrameRGB arguments must be null the first time otherwise it's not good..
459
    // This block is only executed the first time we enter this function.
460 115329f1 Diego Biurrun
    if (0 == ci->pFrameRGB &&
461
        0 == cleanup)
462 21754ce6 Michael Niedermayer
    {
463 115329f1 Diego Biurrun
464
        /*
465 21754ce6 Michael Niedermayer
         * The last three parameters specify the file format, buffer size and format
466
         * parameters; by simply specifying NULL or 0 we ask libavformat to auto-detect
467
         * the format and use a default buffer size. (Didn't work!)
468
         */
469
        if (av_open_input_file(&ci->pFormatCtx, ci->filename, NULL, 0, NULL) != 0) {
470
471
            // Martin says this should not be necessary but it failed for me sending in
472
            // NULL instead of file_iformat to av_open_input_file()
473
            ci->i = strlen(ci->filename);
474
            if (0 == ci->i) {
475 f368375c Marcus Engene
                av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() No filename to watermark vhook\n");
476 21754ce6 Michael Niedermayer
                return -1;
477
            }
478
            while (ci->i > 0) {
479
                if (ci->filename[ci->i] == '.') {
480
                    ci->i++;
481
                    break;
482
                }
483
                ci->i--;
484
            }
485
               ci->p_ext = &(ci->filename[ci->i]);
486
            ci->file_iformat = av_find_input_format (ci->p_ext);
487
            if (0 == ci->file_iformat) {
488 dd933153 Víctor Paesa
                av_log(NULL, AV_LOG_INFO, "get_watermark_picture() attempt to use image2 for [%s]\n", ci->p_ext);
489
                ci->file_iformat = av_find_input_format ("image2");
490
            }
491
            if (0 == ci->file_iformat) {
492 f368375c Marcus Engene
                av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Really failed to find iformat [%s]\n", ci->p_ext);
493 21754ce6 Michael Niedermayer
                return -1;
494
            }
495 115329f1 Diego Biurrun
            // now continues the Martin template.
496
497 21754ce6 Michael Niedermayer
            if (av_open_input_file(&ci->pFormatCtx, ci->filename, ci->file_iformat, 0, NULL)!=0) {
498 f368375c Marcus Engene
                av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to open input file [%s]\n", ci->filename);
499 21754ce6 Michael Niedermayer
                return -1;
500 115329f1 Diego Biurrun
            }
501 21754ce6 Michael Niedermayer
        }
502 115329f1 Diego Biurrun
503
        /*
504 21754ce6 Michael Niedermayer
         * This fills the streams field of the AVFormatContext with valid information.
505
         */
506
        if(av_find_stream_info(ci->pFormatCtx)<0) {
507 f368375c Marcus Engene
            av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find stream info\n");
508 21754ce6 Michael Niedermayer
            return -1;
509
        }
510 115329f1 Diego Biurrun
511 21754ce6 Michael Niedermayer
        /*
512 115329f1 Diego Biurrun
         * As mentioned in the introduction, we'll handle only video streams, not audio
513 21754ce6 Michael Niedermayer
         * streams. To make things nice and easy, we simply use the first video stream we
514
         * find.
515
         */
516
        ci->videoStream=-1;
517
        for(ci->i = 0; ci->i < ci->pFormatCtx->nb_streams; ci->i++)
518 a2cfc4d6 Mike Melanson
            if(ci->pFormatCtx->streams[ci->i]->codec->codec_type==CODEC_TYPE_VIDEO)
519 21754ce6 Michael Niedermayer
            {
520
                ci->videoStream = ci->i;
521
                break;
522
            }
523
        if(ci->videoStream == -1) {
524 f368375c Marcus Engene
            av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find any video stream\n");
525 21754ce6 Michael Niedermayer
            return -1;
526
        }
527 115329f1 Diego Biurrun
528 21754ce6 Michael Niedermayer
        ci->st = ci->pFormatCtx->streams[ci->videoStream];
529 a2cfc4d6 Mike Melanson
        ci->x_size = ci->st->codec->width;
530
        ci->y_size = ci->st->codec->height;
531 115329f1 Diego Biurrun
532 21754ce6 Michael Niedermayer
        // Get a pointer to the codec context for the video stream
533 a2cfc4d6 Mike Melanson
        ci->pCodecCtx = ci->pFormatCtx->streams[ci->videoStream]->codec;
534 115329f1 Diego Biurrun
535
536 21754ce6 Michael Niedermayer
        /*
537
         * OK, so now we've got a pointer to the so-called codec context for our video
538
         * stream, but we still have to find the actual codec and open it.
539 115329f1 Diego Biurrun
         */
540 21754ce6 Michael Niedermayer
        // Find the decoder for the video stream
541
        ci->pCodec = avcodec_find_decoder(ci->pCodecCtx->codec_id);
542
        if(ci->pCodec == NULL) {
543 f368375c Marcus Engene
            av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find any codec\n");
544 21754ce6 Michael Niedermayer
            return -1;
545
        }
546 115329f1 Diego Biurrun
547 21754ce6 Michael Niedermayer
        // Inform the codec that we can handle truncated bitstreams -- i.e.,
548
        // bitstreams where frame boundaries can fall in the middle of packets
549
        if (ci->pCodec->capabilities & CODEC_CAP_TRUNCATED)
550
            ci->pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
551 115329f1 Diego Biurrun
552 21754ce6 Michael Niedermayer
        // Open codec
553
        if(avcodec_open(ci->pCodecCtx, ci->pCodec)<0) {
554 f368375c Marcus Engene
            av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to open codec\n");
555 21754ce6 Michael Niedermayer
            return -1;
556
        }
557 115329f1 Diego Biurrun
558
        // Hack to correct wrong frame rates that seem to be generated by some
559 21754ce6 Michael Niedermayer
        // codecs
560 c0df9d75 Michael Niedermayer
        if (ci->pCodecCtx->time_base.den>1000 && ci->pCodecCtx->time_base.num==1)
561 115329f1 Diego Biurrun
            ci->pCodecCtx->time_base.num=1000;
562
563 21754ce6 Michael Niedermayer
        /*
564
         * Allocate a video frame to store the decoded images in.
565
         */
566
        ci->pFrame = avcodec_alloc_frame();
567 115329f1 Diego Biurrun
568
569 21754ce6 Michael Niedermayer
        /*
570
         * The RGB image pFrameRGB (of type AVFrame *) is allocated like this:
571
         */
572
        // Allocate an AVFrame structure
573
        ci->pFrameRGB=avcodec_alloc_frame();
574
        if(ci->pFrameRGB==NULL) {
575 f368375c Marcus Engene
            av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to alloc pFrameRGB\n");
576 21754ce6 Michael Niedermayer
            return -1;
577
        }
578 115329f1 Diego Biurrun
579 21754ce6 Michael Niedermayer
        // Determine required buffer size and allocate buffer
580 71e445fc Diego Biurrun
        ci->numBytes = avpicture_get_size(PIX_FMT_RGB32, ci->pCodecCtx->width,
581 21754ce6 Michael Niedermayer
            ci->pCodecCtx->height);
582
        ci->buffer = av_malloc(ci->numBytes);
583 115329f1 Diego Biurrun
584 21754ce6 Michael Niedermayer
        // Assign appropriate parts of buffer to image planes in pFrameRGB
585 71e445fc Diego Biurrun
        avpicture_fill((AVPicture *)ci->pFrameRGB, ci->buffer, PIX_FMT_RGB32,
586 115329f1 Diego Biurrun
            ci->pCodecCtx->width, ci->pCodecCtx->height);
587 21754ce6 Michael Niedermayer
    }
588
    // TODO loop, pingpong etc?
589 115329f1 Diego Biurrun
    if (0 == cleanup)
590
    {
591 21754ce6 Michael Niedermayer
//        av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Get a frame\n");
592
        while(av_read_frame(ci->pFormatCtx, &ci->packet)>=0)
593
        {
594
            // Is this a packet from the video stream?
595
            if(ci->packet.stream_index == ci->videoStream)
596
            {
597
                // Decode video frame
598 115329f1 Diego Biurrun
                avcodec_decode_video(ci->pCodecCtx, ci->pFrame, &ci->frameFinished,
599 21754ce6 Michael Niedermayer
                    ci->packet.data, ci->packet.size);
600 115329f1 Diego Biurrun
601 21754ce6 Michael Niedermayer
                // Did we get a video frame?
602
                if(ci->frameFinished)
603
                {
604 71e445fc Diego Biurrun
                    // Convert the image from its native format to RGB32
605 2d7490fc Víctor Paesa
                    ci->watermark_convert_ctx =
606
                        sws_getCachedContext(ci->watermark_convert_ctx,
607
                            ci->pCodecCtx->width, ci->pCodecCtx->height, ci->pCodecCtx->pix_fmt,
608 71e445fc Diego Biurrun
                            ci->pCodecCtx->width, ci->pCodecCtx->height, PIX_FMT_RGB32,
609 2d7490fc Víctor Paesa
                            sws_flags, NULL, NULL, NULL);
610
                    if (ci->watermark_convert_ctx == NULL) {
611
                        av_log(NULL, AV_LOG_ERROR,
612
                              "Cannot initialize the watermark conversion context\n");
613
                        exit(1);
614
                    }
615
// img_convert parameters are          2 first destination, then 4 source
616
// sws_scale   parameters are context, 4 first source,      then 2 destination
617
                    sws_scale(ci->watermark_convert_ctx,
618
                             ci->pFrame->data, ci->pFrame->linesize, 0, ci->pCodecCtx->height,
619
                             ci->pFrameRGB->data, ci->pFrameRGB->linesize);
620 115329f1 Diego Biurrun
621 21754ce6 Michael Niedermayer
                    // Process the video frame (save to disk etc.)
622
                    //fprintf(stderr,"banan() New frame!\n");
623
                    //DoSomethingWithTheImage(ci->pFrameRGB);
624
                    return 0;
625
                }
626
            }
627 115329f1 Diego Biurrun
628 21754ce6 Michael Niedermayer
            // Free the packet that was allocated by av_read_frame
629
            av_free_packet(&ci->packet);
630
        }
631 115329f1 Diego Biurrun
        ci->is_done = 1;
632 21754ce6 Michael Niedermayer
        return 0;
633
    } // if 0 != cleanup
634 115329f1 Diego Biurrun
635
    if (0 != cleanup)
636 21754ce6 Michael Niedermayer
    {
637
        // Free the RGB image
638 b4902c11 Michael Niedermayer
        av_freep(&ci->buffer);
639
        av_freep(&ci->pFrameRGB);
640 115329f1 Diego Biurrun
641 21754ce6 Michael Niedermayer
        // Close the codec
642
        if (0 != ci->pCodecCtx) {
643
            avcodec_close(ci->pCodecCtx);
644
            ci->pCodecCtx = 0;
645
        }
646 115329f1 Diego Biurrun
647 21754ce6 Michael Niedermayer
        // Close the video file
648
        if (0 != ci->pFormatCtx) {
649 115329f1 Diego Biurrun
            av_close_input_file(ci->pFormatCtx);
650 21754ce6 Michael Niedermayer
            ci->pFormatCtx = 0;
651
        }
652 115329f1 Diego Biurrun
653 21754ce6 Michael Niedermayer
        ci->is_done = 0;
654
    }
655
    return 0;
656
}
657
658
659
void parse_arg_file(const char *filename)
660
{
661
}