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.

442 lines
14KB

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