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.

449 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 = 1;
  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_ERROR, "Watermark: Unrecognized argument '%s'\n", argv[optind]);
  98. return -1;
  99. }
  100. }
  101. //
  102. if (0 == ci->filename[0]) {
  103. av_log(NULL, AV_LOG_ERROR, "Watermark: There is no filename specified.\n");
  104. return -1;
  105. }
  106. av_register_all();
  107. return get_watermark_picture(ci, 0);
  108. }
  109. /****************************************************************************
  110. * Why is this a void returning functions? I want to be able to go wrong!
  111. ****************************************************************************/
  112. void Process(void *ctx,
  113. AVPicture *picture,
  114. enum PixelFormat pix_fmt,
  115. int src_width,
  116. int src_height,
  117. int64_t pts)
  118. {
  119. ContextInfo *ci = (ContextInfo *) ctx;
  120. char *buf = 0;
  121. AVPicture picture1;
  122. AVPicture *pict = picture;
  123. AVFrame *pFrameRGB;
  124. int xm_size;
  125. int ym_size;
  126. // int retval = -1;
  127. int x;
  128. int y;
  129. int offs, offsm;
  130. int mpoffs;
  131. uint32_t *p_pixel = 0;
  132. uint32_t pixel_meck;
  133. uint32_t pixel;
  134. uint32_t pixelm;
  135. int tmp;
  136. //?? (void) ci;
  137. if (pix_fmt != PIX_FMT_RGBA32) {
  138. int size;
  139. size = avpicture_get_size(PIX_FMT_RGBA32, src_width, src_height);
  140. buf = av_malloc(size);
  141. avpicture_fill(&picture1, buf, PIX_FMT_RGBA32, src_width, src_height);
  142. if (img_convert(&picture1, PIX_FMT_RGBA32,
  143. picture, pix_fmt, src_width, src_height) < 0) {
  144. av_free(buf);
  145. return;
  146. }
  147. pict = &picture1;
  148. }
  149. /* Insert filter code here */ /* ok */
  150. // Get me next frame
  151. if (0 > get_watermark_picture(ci, 0)) {
  152. return;
  153. }
  154. // These are the three original static variables in the ffmpeg hack.
  155. pFrameRGB = ci->pFrameRGB;
  156. xm_size = ci->x_size;
  157. ym_size = ci->y_size;
  158. // I'll do the *4 => <<2 crap later. Most compilers understand that anyway.
  159. // According to avcodec.h PIX_FMT_RGBA32 is handled in endian specific manner.
  160. for (y=0; y<src_height; y++) {
  161. offs = y * (src_width * 4);
  162. offsm = (((y * ym_size) / src_height) * 4) * xm_size; // offsm first in maskline. byteoffs!
  163. for (x=0; x<src_width; x++) {
  164. mpoffs = offsm + (((x * xm_size) / src_width) * 4);
  165. p_pixel = (uint32_t *)&((pFrameRGB->data[0])[mpoffs]);
  166. pixelm = *p_pixel;
  167. p_pixel = (uint32_t *)&((pict->data[0])[offs]);
  168. pixel = *p_pixel;
  169. // pixelm = *((uint32_t *)&(pFrameRGB->data[mpoffs]));
  170. pixel_meck = pixel & 0xff000000;
  171. // R
  172. tmp = (int)((pixel >> 16) & 0xff) + (int)((pixelm >> 16) & 0xff) - 0x80;
  173. if (tmp > 255) tmp = 255;
  174. if (tmp < 0) tmp = 0;
  175. pixel_meck |= (tmp << 16) & 0xff0000;
  176. // G
  177. tmp = (int)((pixel >> 8) & 0xff) + (int)((pixelm >> 8) & 0xff) - 0x80;
  178. if (tmp > 255) tmp = 255;
  179. if (tmp < 0) tmp = 0;
  180. pixel_meck |= (tmp << 8) & 0xff00;
  181. // B
  182. tmp = (int)((pixel >> 0) & 0xff) + (int)((pixelm >> 0) & 0xff) - 0x80;
  183. if (tmp > 255) tmp = 255;
  184. if (tmp < 0) tmp = 0;
  185. pixel_meck |= (tmp << 0) & 0xff;
  186. // test:
  187. //pixel_meck = pixel & 0xff000000;
  188. //pixel_meck |= (pixelm & 0x00ffffff);
  189. *p_pixel = pixel_meck;
  190. offs += 4;
  191. } // foreach X
  192. } // foreach Y
  193. if (pix_fmt != PIX_FMT_RGBA32) {
  194. if (img_convert(picture, pix_fmt,
  195. &picture1, PIX_FMT_RGBA32, src_width, src_height) < 0) {
  196. }
  197. }
  198. av_free(buf);
  199. }
  200. /****************************************************************************
  201. * When cleanup == 0, we try to get the next frame. If no next frame, nothing
  202. * is done.
  203. *
  204. * This code follows the example on
  205. * http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html
  206. *
  207. * 0 = ok, -1 = error
  208. ****************************************************************************/
  209. int get_watermark_picture(ContextInfo *ci, int cleanup)
  210. {
  211. if (1 == ci->is_done && 0 == cleanup) return 0;
  212. // Yes, *pFrameRGB arguments must be null the first time otherwise it's not good..
  213. // This block is only executed the first time we enter this function.
  214. if (0 == ci->pFrameRGB &&
  215. 0 == cleanup)
  216. {
  217. /*
  218. * The last three parameters specify the file format, buffer size and format
  219. * parameters; by simply specifying NULL or 0 we ask libavformat to auto-detect
  220. * the format and use a default buffer size. (Didn't work!)
  221. */
  222. if (av_open_input_file(&ci->pFormatCtx, ci->filename, NULL, 0, NULL) != 0) {
  223. // Martin says this should not be necessary but it failed for me sending in
  224. // NULL instead of file_iformat to av_open_input_file()
  225. ci->i = strlen(ci->filename);
  226. if (0 == ci->i) {
  227. av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() No filename to watermark vhook\n");
  228. return -1;
  229. }
  230. while (ci->i > 0) {
  231. if (ci->filename[ci->i] == '.') {
  232. ci->i++;
  233. break;
  234. }
  235. ci->i--;
  236. }
  237. ci->p_ext = &(ci->filename[ci->i]);
  238. ci->file_iformat = av_find_input_format (ci->p_ext);
  239. if (0 == ci->file_iformat) {
  240. av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Really failed to find iformat [%s]\n", ci->p_ext);
  241. return -1;
  242. }
  243. // now continues the Martin template.
  244. if (av_open_input_file(&ci->pFormatCtx, ci->filename, ci->file_iformat, 0, NULL)!=0) {
  245. av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to open input file [%s]\n", ci->filename);
  246. return -1;
  247. }
  248. }
  249. /*
  250. * This fills the streams field of the AVFormatContext with valid information.
  251. */
  252. if(av_find_stream_info(ci->pFormatCtx)<0) {
  253. av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find stream info\n");
  254. return -1;
  255. }
  256. /*
  257. * As mentioned in the introduction, we'll handle only video streams, not audio
  258. * streams. To make things nice and easy, we simply use the first video stream we
  259. * find.
  260. */
  261. ci->videoStream=-1;
  262. for(ci->i = 0; ci->i < ci->pFormatCtx->nb_streams; ci->i++)
  263. if(ci->pFormatCtx->streams[ci->i]->codec->codec_type==CODEC_TYPE_VIDEO)
  264. {
  265. ci->videoStream = ci->i;
  266. break;
  267. }
  268. if(ci->videoStream == -1) {
  269. av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find any video stream\n");
  270. return -1;
  271. }
  272. ci->st = ci->pFormatCtx->streams[ci->videoStream];
  273. ci->x_size = ci->st->codec->width;
  274. ci->y_size = ci->st->codec->height;
  275. // Get a pointer to the codec context for the video stream
  276. ci->pCodecCtx = ci->pFormatCtx->streams[ci->videoStream]->codec;
  277. /*
  278. * OK, so now we've got a pointer to the so-called codec context for our video
  279. * stream, but we still have to find the actual codec and open it.
  280. */
  281. // Find the decoder for the video stream
  282. ci->pCodec = avcodec_find_decoder(ci->pCodecCtx->codec_id);
  283. if(ci->pCodec == NULL) {
  284. av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find any codec\n");
  285. return -1;
  286. }
  287. // Inform the codec that we can handle truncated bitstreams -- i.e.,
  288. // bitstreams where frame boundaries can fall in the middle of packets
  289. if (ci->pCodec->capabilities & CODEC_CAP_TRUNCATED)
  290. ci->pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
  291. // Open codec
  292. if(avcodec_open(ci->pCodecCtx, ci->pCodec)<0) {
  293. av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to open codec\n");
  294. return -1;
  295. }
  296. // Hack to correct wrong frame rates that seem to be generated by some
  297. // codecs
  298. if (ci->pCodecCtx->time_base.den>1000 && ci->pCodecCtx->time_base.num==1)
  299. ci->pCodecCtx->time_base.num=1000;
  300. /*
  301. * Allocate a video frame to store the decoded images in.
  302. */
  303. ci->pFrame = avcodec_alloc_frame();
  304. /*
  305. * The RGB image pFrameRGB (of type AVFrame *) is allocated like this:
  306. */
  307. // Allocate an AVFrame structure
  308. ci->pFrameRGB=avcodec_alloc_frame();
  309. if(ci->pFrameRGB==NULL) {
  310. av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to alloc pFrameRGB\n");
  311. return -1;
  312. }
  313. // Determine required buffer size and allocate buffer
  314. ci->numBytes = avpicture_get_size(PIX_FMT_RGBA32, ci->pCodecCtx->width,
  315. ci->pCodecCtx->height);
  316. ci->buffer = av_malloc(ci->numBytes);
  317. // Assign appropriate parts of buffer to image planes in pFrameRGB
  318. avpicture_fill((AVPicture *)ci->pFrameRGB, ci->buffer, PIX_FMT_RGBA32,
  319. ci->pCodecCtx->width, ci->pCodecCtx->height);
  320. }
  321. // TODO loop, pingpong etc?
  322. if (0 == cleanup)
  323. {
  324. // av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Get a frame\n");
  325. while(av_read_frame(ci->pFormatCtx, &ci->packet)>=0)
  326. {
  327. // Is this a packet from the video stream?
  328. if(ci->packet.stream_index == ci->videoStream)
  329. {
  330. // Decode video frame
  331. avcodec_decode_video(ci->pCodecCtx, ci->pFrame, &ci->frameFinished,
  332. ci->packet.data, ci->packet.size);
  333. // Did we get a video frame?
  334. if(ci->frameFinished)
  335. {
  336. // Convert the image from its native format to RGBA32
  337. img_convert((AVPicture *)ci->pFrameRGB, PIX_FMT_RGBA32,
  338. (AVPicture*)(ci->pFrame), ci->pCodecCtx->pix_fmt, ci->pCodecCtx->width,
  339. ci->pCodecCtx->height);
  340. // Process the video frame (save to disk etc.)
  341. //fprintf(stderr,"banan() New frame!\n");
  342. //DoSomethingWithTheImage(ci->pFrameRGB);
  343. return 0;
  344. }
  345. }
  346. // Free the packet that was allocated by av_read_frame
  347. av_free_packet(&ci->packet);
  348. }
  349. ci->is_done = 1;
  350. return 0;
  351. } // if 0 != cleanup
  352. if (0 != cleanup)
  353. {
  354. // Free the RGB image
  355. if (0 != ci->buffer) {
  356. av_free(ci->buffer);
  357. ci->buffer = 0;
  358. }
  359. if (0 != ci->pFrameRGB) {
  360. av_free(ci->pFrameRGB);
  361. ci->pFrameRGB = 0;
  362. }
  363. // Close the codec
  364. if (0 != ci->pCodecCtx) {
  365. avcodec_close(ci->pCodecCtx);
  366. ci->pCodecCtx = 0;
  367. }
  368. // Close the video file
  369. if (0 != ci->pFormatCtx) {
  370. av_close_input_file(ci->pFormatCtx);
  371. ci->pFormatCtx = 0;
  372. }
  373. ci->is_done = 0;
  374. }
  375. return 0;
  376. }
  377. void parse_arg_file(const char *filename)
  378. {
  379. }