You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

448 lines
15KB

  1. /*
  2. * Watermark Hook
  3. * Copyright (c) 2005 Marcus Engene myfirstname(at)mylastname.se
  4. *
  5. * The watermarkpicture works like this. (Assuming colorintencities 0..0xff)
  6. * Per color do this:
  7. * If mask color is 0x80, no change to original frame.
  8. * If mask color is < 0x80 the abs difference is subtracted from frame. If
  9. * result < 0, result = 0
  10. * If mask color is > 0x80 the abs difference is added to frame. If result
  11. * > 0xff, result = 0xff
  12. *
  13. * This way a mask that is visible both in light pictures and in dark can be
  14. * made (fex by using a picture generated by gimp and the bump map tool).
  15. *
  16. * An example watermark file is at
  17. * http://engene.se/ffmpeg_watermark.gif
  18. *
  19. * Example usage:
  20. * ffmpeg -i infile -vhook '/path/watermark.so -f wm.gif' out.mov
  21. *
  22. * Note that the entire vhook argument is encapsulated in ''. This
  23. * way, arguments to the vhook won't be mixed up with those to ffmpeg.
  24. *
  25. * This library is free software; you can redistribute it and/or
  26. * modify it under the terms of the GNU Lesser General Public
  27. * License as published by the Free Software Foundation; either
  28. * version 2 of the License, or (at your option) any later version.
  29. *
  30. * This library is distributed in the hope that it will be useful,
  31. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  32. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  33. * Lesser General Public License for more details.
  34. *
  35. * You should have received a copy of the GNU Lesser General Public
  36. * License along with this library; if not, write to the Free Software
  37. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  38. */
  39. //#include <stdlib.h>
  40. //#include <fcntl.h>
  41. #include <unistd.h>
  42. #include <stdarg.h>
  43. #include "common.h"
  44. #include "avformat.h"
  45. #include "framehook.h"
  46. typedef struct {
  47. char filename[2000];
  48. int x_size;
  49. int y_size;
  50. /* get_watermark_picture() variables */
  51. AVFormatContext *pFormatCtx;
  52. const char *p_ext;
  53. int videoStream;
  54. int frameFinished;
  55. AVCodecContext *pCodecCtx;
  56. AVCodec *pCodec;
  57. AVFrame *pFrame;
  58. AVPacket packet;
  59. int numBytes;
  60. uint8_t *buffer;
  61. int i;
  62. AVInputFormat *file_iformat;
  63. AVStream *st;
  64. int is_done;
  65. AVFrame *pFrameRGB;
  66. } ContextInfo;
  67. int get_watermark_picture(ContextInfo *ci, int cleanup);
  68. /****************************************************************************
  69. *
  70. ****************************************************************************/
  71. void Release(void *ctx)
  72. {
  73. ContextInfo *ci;
  74. ci = (ContextInfo *) ctx;
  75. if (ci) get_watermark_picture(ci, 1);
  76. if (ctx)
  77. av_free(ctx);
  78. }
  79. /****************************************************************************
  80. *
  81. ****************************************************************************/
  82. int Configure(void **ctxp, int argc, char *argv[])
  83. {
  84. ContextInfo *ci;
  85. int c;
  86. if (0 == (*ctxp = av_mallocz(sizeof(ContextInfo)))) return -1;
  87. ci = (ContextInfo *) *ctxp;
  88. optind = 0;
  89. // Struct is mallocz:ed so no need to reset.
  90. while ((c = getopt(argc, argv, "f:")) > 0) {
  91. switch (c) {
  92. case 'f':
  93. strncpy(ci->filename, optarg, 1999);
  94. ci->filename[1999] = 0;
  95. break;
  96. default:
  97. av_log(NULL, AV_LOG_DEBUG, "Unrecognized argument '%s'\n", argv[optind]);
  98. return -1;
  99. }
  100. }
  101. //
  102. if (0 == ci->filename[0]) return -1;
  103. av_register_all();
  104. return get_watermark_picture(ci, 0);
  105. return 0;
  106. }
  107. /****************************************************************************
  108. * Why is this a void returning functions? I want to be able to go wrong!
  109. ****************************************************************************/
  110. void Process(void *ctx,
  111. AVPicture *picture,
  112. enum PixelFormat pix_fmt,
  113. int src_width,
  114. int src_height,
  115. int64_t pts)
  116. {
  117. ContextInfo *ci = (ContextInfo *) ctx;
  118. char *buf = 0;
  119. AVPicture picture1;
  120. AVPicture *pict = picture;
  121. AVFrame *pFrameRGB;
  122. int xm_size;
  123. int ym_size;
  124. // int retval = -1;
  125. int x;
  126. int y;
  127. int offs, offsm;
  128. int mpoffs;
  129. uint32_t *p_pixel = 0;
  130. uint32_t pixel_meck;
  131. uint32_t pixel;
  132. uint32_t pixelm;
  133. int tmp;
  134. //?? (void) ci;
  135. if (pix_fmt != PIX_FMT_RGBA32) {
  136. int size;
  137. size = avpicture_get_size(PIX_FMT_RGBA32, src_width, src_height);
  138. buf = av_malloc(size);
  139. avpicture_fill(&picture1, buf, PIX_FMT_RGBA32, src_width, src_height);
  140. if (img_convert(&picture1, PIX_FMT_RGBA32,
  141. picture, pix_fmt, src_width, src_height) < 0) {
  142. av_free(buf);
  143. return;
  144. }
  145. pict = &picture1;
  146. }
  147. /* Insert filter code here */ /* ok */
  148. // Get me next frame
  149. if (0 > get_watermark_picture(ci, 0)) {
  150. return;
  151. }
  152. // These are the three original static variables in the ffmpeg hack.
  153. pFrameRGB = ci->pFrameRGB;
  154. xm_size = ci->x_size;
  155. ym_size = ci->y_size;
  156. // I'll do the *4 => <<2 crap later. Most compilers understand that anyway.
  157. // According to avcodec.h PIX_FMT_RGBA32 is handled in endian specific manner.
  158. for (y=0; y<src_height; y++) {
  159. offs = y * (src_width * 4);
  160. offsm = (((y * ym_size) / src_height) * 4) * xm_size; // offsm first in maskline. byteoffs!
  161. for (x=0; x<src_width; x++) {
  162. mpoffs = offsm + (((x * xm_size) / src_width) * 4);
  163. p_pixel = (uint32_t *)&((pFrameRGB->data[0])[mpoffs]);
  164. pixelm = *p_pixel;
  165. p_pixel = (uint32_t *)&((pict->data[0])[offs]);
  166. pixel = *p_pixel;
  167. // pixelm = *((uint32_t *)&(pFrameRGB->data[mpoffs]));
  168. pixel_meck = pixel & 0xff000000;
  169. // R
  170. tmp = (int)((pixel >> 16) & 0xff) + (int)((pixelm >> 16) & 0xff) - 0x80;
  171. if (tmp > 255) tmp = 255;
  172. if (tmp < 0) tmp = 0;
  173. pixel_meck |= (tmp << 16) & 0xff0000;
  174. // G
  175. tmp = (int)((pixel >> 8) & 0xff) + (int)((pixelm >> 8) & 0xff) - 0x80;
  176. if (tmp > 255) tmp = 255;
  177. if (tmp < 0) tmp = 0;
  178. pixel_meck |= (tmp << 8) & 0xff00;
  179. // B
  180. tmp = (int)((pixel >> 0) & 0xff) + (int)((pixelm >> 0) & 0xff) - 0x80;
  181. if (tmp > 255) tmp = 255;
  182. if (tmp < 0) tmp = 0;
  183. pixel_meck |= (tmp << 0) & 0xff;
  184. // test:
  185. //pixel_meck = pixel & 0xff000000;
  186. //pixel_meck |= (pixelm & 0x00ffffff);
  187. *p_pixel = pixel_meck;
  188. offs += 4;
  189. } // foreach X
  190. } // foreach Y
  191. if (pix_fmt != PIX_FMT_RGBA32) {
  192. if (img_convert(picture, pix_fmt,
  193. &picture1, PIX_FMT_RGBA32, src_width, src_height) < 0) {
  194. }
  195. }
  196. av_free(buf);
  197. }
  198. /****************************************************************************
  199. * When cleanup == 0, we try to get the next frame. If no next frame, nothing
  200. * is done.
  201. *
  202. * This code follows the example on
  203. * http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html
  204. *
  205. * 0 = ok, -1 = error
  206. ****************************************************************************/
  207. int get_watermark_picture(ContextInfo *ci, int cleanup)
  208. {
  209. if (1 == ci->is_done && 0 == cleanup) return 0;
  210. // Yes, *pFrameRGB arguments must be null the first time otherwise it's not good..
  211. // This block is only executed the first time we enter this function.
  212. if (0 == ci->pFrameRGB &&
  213. 0 == cleanup)
  214. {
  215. /*
  216. * The last three parameters specify the file format, buffer size and format
  217. * parameters; by simply specifying NULL or 0 we ask libavformat to auto-detect
  218. * the format and use a default buffer size. (Didn't work!)
  219. */
  220. if (av_open_input_file(&ci->pFormatCtx, ci->filename, NULL, 0, NULL) != 0) {
  221. // Martin says this should not be necessary but it failed for me sending in
  222. // NULL instead of file_iformat to av_open_input_file()
  223. ci->i = strlen(ci->filename);
  224. if (0 == ci->i) {
  225. av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() No filename to watermark vhook\n");
  226. return -1;
  227. }
  228. while (ci->i > 0) {
  229. if (ci->filename[ci->i] == '.') {
  230. ci->i++;
  231. break;
  232. }
  233. ci->i--;
  234. }
  235. ci->p_ext = &(ci->filename[ci->i]);
  236. ci->file_iformat = av_find_input_format (ci->p_ext);
  237. if (0 == ci->file_iformat) {
  238. av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Really failed to find iformat [%s]\n", ci->p_ext);
  239. return -1;
  240. }
  241. // now continues the Martin template.
  242. if (av_open_input_file(&ci->pFormatCtx, ci->filename, ci->file_iformat, 0, NULL)!=0) {
  243. av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Failed to open input file [%s]\n", ci->filename);
  244. return -1;
  245. }
  246. }
  247. /*
  248. * This fills the streams field of the AVFormatContext with valid information.
  249. */
  250. if(av_find_stream_info(ci->pFormatCtx)<0) {
  251. av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Failed to find stream info\n");
  252. return -1;
  253. }
  254. /*
  255. * As mentioned in the introduction, we'll handle only video streams, not audio
  256. * streams. To make things nice and easy, we simply use the first video stream we
  257. * find.
  258. */
  259. ci->videoStream=-1;
  260. for(ci->i = 0; ci->i < ci->pFormatCtx->nb_streams; ci->i++)
  261. if(ci->pFormatCtx->streams[ci->i]->codec->codec_type==CODEC_TYPE_VIDEO)
  262. {
  263. ci->videoStream = ci->i;
  264. break;
  265. }
  266. if(ci->videoStream == -1) {
  267. av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Failed to find any video stream\n");
  268. return -1;
  269. }
  270. ci->st = ci->pFormatCtx->streams[ci->videoStream];
  271. ci->x_size = ci->st->codec->width;
  272. ci->y_size = ci->st->codec->height;
  273. // Get a pointer to the codec context for the video stream
  274. ci->pCodecCtx = ci->pFormatCtx->streams[ci->videoStream]->codec;
  275. /*
  276. * OK, so now we've got a pointer to the so-called codec context for our video
  277. * stream, but we still have to find the actual codec and open it.
  278. */
  279. // Find the decoder for the video stream
  280. ci->pCodec = avcodec_find_decoder(ci->pCodecCtx->codec_id);
  281. if(ci->pCodec == NULL) {
  282. av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Failed to find any codec\n");
  283. return -1;
  284. }
  285. // Inform the codec that we can handle truncated bitstreams -- i.e.,
  286. // bitstreams where frame boundaries can fall in the middle of packets
  287. if (ci->pCodec->capabilities & CODEC_CAP_TRUNCATED)
  288. ci->pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
  289. // Open codec
  290. if(avcodec_open(ci->pCodecCtx, ci->pCodec)<0) {
  291. av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Failed to open codec\n");
  292. return -1;
  293. }
  294. // Hack to correct wrong frame rates that seem to be generated by some
  295. // codecs
  296. if (ci->pCodecCtx->time_base.den>1000 && ci->pCodecCtx->time_base.num==1)
  297. ci->pCodecCtx->time_base.num=1000;
  298. /*
  299. * Allocate a video frame to store the decoded images in.
  300. */
  301. ci->pFrame = avcodec_alloc_frame();
  302. /*
  303. * The RGB image pFrameRGB (of type AVFrame *) is allocated like this:
  304. */
  305. // Allocate an AVFrame structure
  306. ci->pFrameRGB=avcodec_alloc_frame();
  307. if(ci->pFrameRGB==NULL) {
  308. av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Failed to alloc pFrameRGB\n");
  309. return -1;
  310. }
  311. // Determine required buffer size and allocate buffer
  312. ci->numBytes = avpicture_get_size(PIX_FMT_RGBA32, ci->pCodecCtx->width,
  313. ci->pCodecCtx->height);
  314. ci->buffer = av_malloc(ci->numBytes);
  315. // Assign appropriate parts of buffer to image planes in pFrameRGB
  316. avpicture_fill((AVPicture *)ci->pFrameRGB, ci->buffer, PIX_FMT_RGBA32,
  317. ci->pCodecCtx->width, ci->pCodecCtx->height);
  318. }
  319. // TODO loop, pingpong etc?
  320. if (0 == cleanup)
  321. {
  322. // av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Get a frame\n");
  323. while(av_read_frame(ci->pFormatCtx, &ci->packet)>=0)
  324. {
  325. // Is this a packet from the video stream?
  326. if(ci->packet.stream_index == ci->videoStream)
  327. {
  328. // Decode video frame
  329. avcodec_decode_video(ci->pCodecCtx, ci->pFrame, &ci->frameFinished,
  330. ci->packet.data, ci->packet.size);
  331. // Did we get a video frame?
  332. if(ci->frameFinished)
  333. {
  334. // Convert the image from its native format to RGBA32
  335. img_convert((AVPicture *)ci->pFrameRGB, PIX_FMT_RGBA32,
  336. (AVPicture*)(ci->pFrame), ci->pCodecCtx->pix_fmt, ci->pCodecCtx->width,
  337. ci->pCodecCtx->height);
  338. // Process the video frame (save to disk etc.)
  339. //fprintf(stderr,"banan() New frame!\n");
  340. //DoSomethingWithTheImage(ci->pFrameRGB);
  341. return 0;
  342. }
  343. }
  344. // Free the packet that was allocated by av_read_frame
  345. av_free_packet(&ci->packet);
  346. }
  347. ci->is_done = 1;
  348. return 0;
  349. } // if 0 != cleanup
  350. if (0 != cleanup)
  351. {
  352. // Free the RGB image
  353. if (0 != ci->buffer) {
  354. av_free(ci->buffer);
  355. ci->buffer = 0;
  356. }
  357. if (0 != ci->pFrameRGB) {
  358. av_free(ci->pFrameRGB);
  359. ci->pFrameRGB = 0;
  360. }
  361. // Close the codec
  362. if (0 != ci->pCodecCtx) {
  363. avcodec_close(ci->pCodecCtx);
  364. ci->pCodecCtx = 0;
  365. }
  366. // Close the video file
  367. if (0 != ci->pFormatCtx) {
  368. av_close_input_file(ci->pFormatCtx);
  369. ci->pFormatCtx = 0;
  370. }
  371. ci->is_done = 0;
  372. }
  373. return 0;
  374. }
  375. void parse_arg_file(const char *filename)
  376. {
  377. }