Statistics
| Branch: | Revision:

ffmpeg / vhook / watermark.c @ ed77a6c9

History | View | Annotate | Download (22.6 KB)

1
/*
2
 * Watermark Hook
3
 * Copyright (c) 2005 Marcus Engene myfirstname(at)mylastname.se
4
 *
5
 * parameters for watermark:
6
 *  -m nbr = nbr is 0..1. 0 is the default mode, see below.
7
 *  -t nbr = nbr is six digit hex. Threshold.
8
 *  -f file = file is the watermark image filename. You must specify this!
9
 *
10
 * MODE 0:
11
 * The watermark picture works like this (assuming color intensities 0..0xff):
12
 * Per color do this:
13
 * 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
 * result < 0, result = 0
16
 * If mask color is > 0x80 the abs difference is added to the frame. If result
17
 * > 0xff, result = 0xff
18
 *
19
 * 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
 *
22
 * This way a mask that is visible both in light pictures and in dark can be
23
 * made (fex by using a picture generated by Gimp and the bump map tool).
24
 *
25
 * An example watermark file is at
26
 * http://engene.se/ffmpeg_watermark.gif
27
 *
28
 * MODE 1:
29
 * Per color do this:
30
 * If mask color > threshold color then the watermark pixel is used.
31
 *
32
 * Example usage:
33
 *  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
 *
36
 * Note that the entire vhook argument is encapsulated in ''. This
37
 * way, arguments to the vhook won't be mixed up with those for ffmpeg.
38
 *
39
 * This file is part of FFmpeg.
40
 *
41
 * FFmpeg is free software; you can redistribute it and/or
42
 * modify it under the terms of the GNU Lesser General Public
43
 * License as published by the Free Software Foundation; either
44
 * version 2.1 of the License, or (at your option) any later version.
45
 *
46
 * FFmpeg is distributed in the hope that it will be useful,
47
 * 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
 * License along with FFmpeg; if not, write to the Free Software
53
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
54
 */
55

    
56
#include <stdlib.h>
57
//#include <fcntl.h>
58
#include <unistd.h>
59
#include <stdarg.h>
60

    
61
#include "common.h"
62
#include "avformat.h"
63

    
64
#include "framehook.h"
65
#include "cmdutils.h"
66
#include "swscale.h"
67

    
68
static int sws_flags = SWS_BICUBIC;
69

    
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
    AVCodecContext *pCodecCtx;
81
    AVCodec        *pCodec;
82
    AVFrame        *pFrame;
83
    AVPacket        packet;
84
    int             numBytes;
85
    uint8_t        *buffer;
86
    int             i;
87
    AVInputFormat  *file_iformat;
88
    AVStream       *st;
89
    int             is_done;
90
    AVFrame        *pFrameRGB;
91
    int             thrR;
92
    int             thrG;
93
    int             thrB;
94
    int             mode;
95

    
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
} ContextInfo;
103

    
104
int get_watermark_picture(ContextInfo *ci, int cleanup);
105

    
106

    
107
/****************************************************************************
108
 *
109
 ****************************************************************************/
110
void Release(void *ctx)
111
{
112
    ContextInfo *ci;
113
    ci = (ContextInfo *) ctx;
114

    
115
    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
    av_free(ctx);
122
}
123

    
124

    
125
/****************************************************************************
126
 *
127
 ****************************************************************************/
128
int Configure(void **ctxp, int argc, char *argv[])
129
{
130
    ContextInfo *ci;
131
    int c;
132
    int tmp = 0;
133

    
134
    if (0 == (*ctxp = av_mallocz(sizeof(ContextInfo)))) return -1;
135
    ci = (ContextInfo *) *ctxp;
136

    
137
    optind = 1;
138

    
139
    // Struct is mallocz:ed so no need to reset.
140
    ci->thrR = 0x80;
141
    ci->thrG = 0x80;
142
    ci->thrB = 0x80;
143

    
144
    while ((c = getopt(argc, argv, "f:m:t:")) > 0) {
145
        switch (c) {
146
            case 'f':
147
                strncpy(ci->filename, optarg, 1999);
148
                ci->filename[1999] = 0;
149
                break;
150
            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
            default:
163
                av_log(NULL, AV_LOG_ERROR, "Watermark: Unrecognized argument '%s'\n", argv[optind]);
164
                return -1;
165
        }
166
    }
167

    
168
    //
169
    if (0 == ci->filename[0]) {
170
        av_log(NULL, AV_LOG_ERROR, "Watermark: There is no filename specified.\n");
171
        return -1;
172
    }
173

    
174
    av_register_all();
175
    return get_watermark_picture(ci, 0);
176
}
177

    
178

    
179
/****************************************************************************
180
 * For mode 0 (the original one)
181
 ****************************************************************************/
182
static void Process0(void *ctx,
183
              AVPicture *picture,
184
              enum PixelFormat pix_fmt,
185
              int src_width,
186
              int src_height,
187
              int64_t pts)
188
{
189
    ContextInfo *ci = (ContextInfo *) ctx;
190
    char *buf = 0;
191
    AVPicture picture1;
192
    AVPicture *pict = picture;
193

    
194
    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
    int tmp;
207
    int thrR = ci->thrR;
208
    int thrG = ci->thrG;
209
    int thrB = ci->thrB;
210

    
211
    if (pix_fmt != PIX_FMT_RGB32) {
212
        int size;
213

    
214
        size = avpicture_get_size(PIX_FMT_RGB32, src_width, src_height);
215
        buf = av_malloc(size);
216

    
217
        avpicture_fill(&picture1, buf, PIX_FMT_RGB32, src_width, src_height);
218

    
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
                                    src_width, src_height, PIX_FMT_RGB32,
223
                                    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
            return;
228
        }
229

    
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
        pict = &picture1;
237
    }
238

    
239
    /* Insert filter code here */ /* ok */
240

    
241
    // Get me next frame
242
    if (0 > get_watermark_picture(ci, 0)) {
243
        return;
244
    }
245
    // 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

    
250
    // I'll do the *4 => <<2 crap later. Most compilers understand that anyway.
251
    // According to avcodec.h PIX_FMT_RGB32 is handled in endian specific manner.
252
    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
            tmp = (int)((pixel >> 16) & 0xff) + (int)((pixelm >> 16) & 0xff) - thrR;
266
            if (tmp > 255) tmp = 255;
267
            if (tmp < 0) tmp = 0;
268
            pixel_meck |= (tmp << 16) & 0xff0000;
269
            // G
270
            tmp = (int)((pixel >> 8) & 0xff) + (int)((pixelm >> 8) & 0xff) - thrG;
271
            if (tmp > 255) tmp = 255;
272
            if (tmp < 0) tmp = 0;
273
            pixel_meck |= (tmp << 8) & 0xff00;
274
            // B
275
            tmp = (int)((pixel >> 0) & 0xff) + (int)((pixelm >> 0) & 0xff) - thrB;
276
            if (tmp > 255) tmp = 255;
277
            if (tmp < 0) tmp = 0;
278
            pixel_meck |= (tmp << 0) & 0xff;
279

    
280

    
281
            // test:
282
            //pixel_meck = pixel & 0xff000000;
283
            //pixel_meck |= (pixelm & 0x00ffffff);
284

    
285
            *p_pixel = pixel_meck;
286

    
287
            offs += 4;
288
        } // foreach X
289
    } // foreach Y
290

    
291

    
292

    
293

    
294
    if (pix_fmt != PIX_FMT_RGB32) {
295
        ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
296
                                      src_width, src_height, PIX_FMT_RGB32,
297
                                      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
            return;
303
        }
304
// 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
    }
310

    
311
    av_free(buf);
312
}
313

    
314

    
315
/****************************************************************************
316
 * For mode 1 (the original one)
317
 ****************************************************************************/
318
static void Process1(void *ctx,
319
              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
    if (pix_fmt != PIX_FMT_RGB32) {
343
        int size;
344

    
345
        size = avpicture_get_size(PIX_FMT_RGB32, src_width, src_height);
346
        buf = av_malloc(size);
347

    
348
        avpicture_fill(&picture1, buf, PIX_FMT_RGB32, src_width, src_height);
349

    
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
                                    src_width, src_height, PIX_FMT_RGB32,
354
                                    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
            return;
359
        }
360

    
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
        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
    // According to avcodec.h PIX_FMT_RGB32 is handled in endian specific manner.
383
    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
    if (pix_fmt != PIX_FMT_RGB32) {
406
        ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
407
                                      src_width, src_height, PIX_FMT_RGB32,
408
                                      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
            return;
414
        }
415
// 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
    }
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
        Process1(ctx, picture, pix_fmt, src_width, src_height, pts);
439
    } else {
440
        Process0(ctx, picture, pix_fmt, src_width, src_height, pts);
441
    }
442
}
443

    
444

    
445
/****************************************************************************
446
 * When cleanup == 0, we try to get the next frame. If no next frame, nothing
447
 * is done.
448
 *
449
 * This code follows the example on
450
 * 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
    if (0 == ci->pFrameRGB &&
461
        0 == cleanup)
462
    {
463

    
464
        /*
465
         * 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
                av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() No filename to watermark vhook\n");
476
                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
                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
                av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Really failed to find iformat [%s]\n", ci->p_ext);
493
                return -1;
494
            }
495
            // now continues the Martin template.
496

    
497
            if (av_open_input_file(&ci->pFormatCtx, ci->filename, ci->file_iformat, 0, NULL)!=0) {
498
                av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to open input file [%s]\n", ci->filename);
499
                return -1;
500
            }
501
        }
502

    
503
        /*
504
         * This fills the streams field of the AVFormatContext with valid information.
505
         */
506
        if(av_find_stream_info(ci->pFormatCtx)<0) {
507
            av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find stream info\n");
508
            return -1;
509
        }
510

    
511
        /*
512
         * As mentioned in the introduction, we'll handle only video streams, not audio
513
         * 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
            if(ci->pFormatCtx->streams[ci->i]->codec->codec_type==CODEC_TYPE_VIDEO)
519
            {
520
                ci->videoStream = ci->i;
521
                break;
522
            }
523
        if(ci->videoStream == -1) {
524
            av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find any video stream\n");
525
            return -1;
526
        }
527

    
528
        ci->st = ci->pFormatCtx->streams[ci->videoStream];
529
        ci->x_size = ci->st->codec->width;
530
        ci->y_size = ci->st->codec->height;
531

    
532
        // Get a pointer to the codec context for the video stream
533
        ci->pCodecCtx = ci->pFormatCtx->streams[ci->videoStream]->codec;
534

    
535

    
536
        /*
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
         */
540
        // Find the decoder for the video stream
541
        ci->pCodec = avcodec_find_decoder(ci->pCodecCtx->codec_id);
542
        if(ci->pCodec == NULL) {
543
            av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find any codec\n");
544
            return -1;
545
        }
546

    
547

    
548
        // Open codec
549
        if(avcodec_open(ci->pCodecCtx, ci->pCodec)<0) {
550
            av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to open codec\n");
551
            return -1;
552
        }
553

    
554
        // Hack to correct wrong frame rates that seem to be generated by some
555
        // codecs
556
        if (ci->pCodecCtx->time_base.den>1000 && ci->pCodecCtx->time_base.num==1)
557
            ci->pCodecCtx->time_base.num=1000;
558

    
559
        /*
560
         * Allocate a video frame to store the decoded images in.
561
         */
562
        ci->pFrame = avcodec_alloc_frame();
563

    
564

    
565
        /*
566
         * The RGB image pFrameRGB (of type AVFrame *) is allocated like this:
567
         */
568
        // Allocate an AVFrame structure
569
        ci->pFrameRGB=avcodec_alloc_frame();
570
        if(ci->pFrameRGB==NULL) {
571
            av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to alloc pFrameRGB\n");
572
            return -1;
573
        }
574

    
575
        // Determine required buffer size and allocate buffer
576
        ci->numBytes = avpicture_get_size(PIX_FMT_RGB32, ci->pCodecCtx->width,
577
            ci->pCodecCtx->height);
578
        ci->buffer = av_malloc(ci->numBytes);
579

    
580
        // Assign appropriate parts of buffer to image planes in pFrameRGB
581
        avpicture_fill((AVPicture *)ci->pFrameRGB, ci->buffer, PIX_FMT_RGB32,
582
            ci->pCodecCtx->width, ci->pCodecCtx->height);
583
    }
584
    // TODO loop, pingpong etc?
585
    if (0 == cleanup)
586
    {
587
//        av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Get a frame\n");
588
        while(av_read_frame(ci->pFormatCtx, &ci->packet)>=0)
589
        {
590
            // Is this a packet from the video stream?
591
            if(ci->packet.stream_index == ci->videoStream)
592
            {
593
                // Decode video frame
594
                avcodec_decode_video(ci->pCodecCtx, ci->pFrame, &ci->frameFinished,
595
                    ci->packet.data, ci->packet.size);
596

    
597
                // Did we get a video frame?
598
                if(ci->frameFinished)
599
                {
600
                    // Convert the image from its native format to RGB32
601
                    ci->watermark_convert_ctx =
602
                        sws_getCachedContext(ci->watermark_convert_ctx,
603
                            ci->pCodecCtx->width, ci->pCodecCtx->height, ci->pCodecCtx->pix_fmt,
604
                            ci->pCodecCtx->width, ci->pCodecCtx->height, PIX_FMT_RGB32,
605
                            sws_flags, NULL, NULL, NULL);
606
                    if (ci->watermark_convert_ctx == NULL) {
607
                        av_log(NULL, AV_LOG_ERROR,
608
                              "Cannot initialize the watermark conversion context\n");
609
                        return -1;
610
                    }
611
// img_convert parameters are          2 first destination, then 4 source
612
// sws_scale   parameters are context, 4 first source,      then 2 destination
613
                    sws_scale(ci->watermark_convert_ctx,
614
                             ci->pFrame->data, ci->pFrame->linesize, 0, ci->pCodecCtx->height,
615
                             ci->pFrameRGB->data, ci->pFrameRGB->linesize);
616

    
617
                    // Process the video frame (save to disk etc.)
618
                    //fprintf(stderr,"banan() New frame!\n");
619
                    //DoSomethingWithTheImage(ci->pFrameRGB);
620
                    return 0;
621
                }
622
            }
623

    
624
            // Free the packet that was allocated by av_read_frame
625
            av_free_packet(&ci->packet);
626
        }
627
        ci->is_done = 1;
628
        return 0;
629
    } // if 0 != cleanup
630

    
631
    if (0 != cleanup)
632
    {
633
        // Free the RGB image
634
        av_freep(&ci->buffer);
635
        av_freep(&ci->pFrameRGB);
636

    
637
        // Close the codec
638
        if (0 != ci->pCodecCtx) {
639
            avcodec_close(ci->pCodecCtx);
640
            ci->pCodecCtx = 0;
641
        }
642

    
643
        // Close the video file
644
        if (0 != ci->pFormatCtx) {
645
            av_close_input_file(ci->pFormatCtx);
646
            ci->pFormatCtx = 0;
647
        }
648

    
649
        ci->is_done = 0;
650
    }
651
    return 0;
652
}
653

    
654

    
655
void parse_arg_file(const char *filename)
656
{
657
}