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