您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

213 行
5.8 KiB

  1. /*
  2. * storyboard generate a storyboard from a movie
  3. * Copyright (c) 2009 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This program is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. #include "config.h"
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <avcodec.h>
  19. #include <avformat.h>
  20. #include <swscale.h>
  21. #include <pipi.h>
  22. #define STEP 15
  23. #define TWIDTH 90
  24. #define THEIGHT 60
  25. #define TCOLS 10
  26. #define TROWS 50
  27. #define NTHUMBS (TCOLS*TROWS)
  28. static int similar(uint8_t *img1, uint8_t *img2);
  29. int main(int argc, char *argv[])
  30. {
  31. char fmtstr[1024];
  32. AVPacket packet;
  33. AVFormatContext *fmt;
  34. AVCodecContext *ctx;
  35. AVCodec *codec;
  36. AVFrame *frame;
  37. struct SwsContext *sws = NULL;
  38. pipi_image_t *image;
  39. pipi_pixels_t *p;
  40. uint8_t *buffer;
  41. char *parser;
  42. int stream, i, n = 0, k = 0, idx = 0;
  43. if(argc < 2)
  44. return EXIT_FAILURE;
  45. parser = strrchr(argv[1], '/');
  46. strcpy(fmtstr, parser ? parser + 1 : argv[1]);
  47. parser = strrchr(fmtstr, '.');
  48. if(parser)
  49. *parser = '\0';
  50. strcat(fmtstr, ".t%02i.jpeg");
  51. image = pipi_new(TWIDTH * TCOLS, THEIGHT * TROWS);
  52. p = pipi_get_pixels(image, PIPI_PIXELS_RGBA_U8);
  53. buffer = (uint8_t *)p->pixels;
  54. av_register_all();
  55. if(av_open_input_file(&fmt, argv[1], NULL, 0, NULL) != 0)
  56. return EXIT_FAILURE;
  57. if(av_find_stream_info(fmt) < 0 )
  58. return EXIT_FAILURE;
  59. stream = -1;
  60. for(i = 0; stream == -1 && i < (int)fmt->nb_streams; i++)
  61. if(fmt->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
  62. stream = i;
  63. if(stream == -1)
  64. return EXIT_FAILURE;
  65. ctx = fmt->streams[stream]->codec;
  66. codec = avcodec_find_decoder(ctx->codec_id);
  67. if(codec == NULL)
  68. return EXIT_FAILURE;
  69. if(avcodec_open(ctx, codec) < 0)
  70. return EXIT_FAILURE;
  71. frame = avcodec_alloc_frame();
  72. for(;;)
  73. {
  74. int finished, ret;
  75. ret = av_read_frame(fmt, &packet);
  76. if(idx == NTHUMBS || (idx > 0 && ret < 0))
  77. {
  78. char buf[1024];
  79. sprintf(buf, fmtstr, k++);
  80. printf("saving %i thumbs in %s\n", idx, buf);
  81. pipi_save(image, buf);
  82. memset(buffer, 0, TWIDTH * TCOLS * THEIGHT * TROWS * 4);
  83. idx = 0;
  84. }
  85. if(ret < 0)
  86. break;
  87. if(packet.stream_index != stream)
  88. {
  89. av_free_packet(&packet);
  90. continue;
  91. }
  92. avcodec_decode_video(ctx, frame, &finished, packet.data, packet.size);
  93. if(!finished)
  94. {
  95. av_free_packet(&packet);
  96. continue;
  97. }
  98. /* Only process every 20th image */
  99. if((++n % STEP) == STEP / 2)
  100. {
  101. uint8_t *start;
  102. int pitch = TWIDTH * TCOLS * 4;
  103. int good = 1;
  104. start = buffer + (idx % TCOLS) * TWIDTH * 4
  105. + (idx / TCOLS) * TWIDTH * TCOLS * 4 * THEIGHT;
  106. if(!sws)
  107. sws = sws_getContext(ctx->width, ctx->height, ctx->pix_fmt,
  108. TWIDTH, THEIGHT, PIX_FMT_RGB32,
  109. SWS_BICUBIC, NULL, NULL, NULL);
  110. sws_scale(sws, frame->data, frame->linesize, 0, ctx->height,
  111. &start, &pitch);
  112. if(idx > 0)
  113. {
  114. uint8_t *prev;
  115. if(idx % TCOLS)
  116. prev = start - TWIDTH * 4;
  117. else
  118. prev = start + (TCOLS - 1) * TWIDTH * 4
  119. - TWIDTH * TCOLS * 4 * THEIGHT;
  120. /* Now check whether the new image is really different
  121. * from the previous one (> 10% pixel changes) */
  122. if(similar(start, prev))
  123. good = 0;
  124. }
  125. if(good)
  126. {
  127. idx++;
  128. }
  129. }
  130. av_free_packet(&packet);
  131. }
  132. return EXIT_SUCCESS;
  133. }
  134. static int similar(uint8_t *img1, uint8_t *img2)
  135. {
  136. int x, y, t, a, b, changed = 0;
  137. for(y = 1; y < THEIGHT - 1; y++)
  138. for(x = 1; x < TWIDTH - 1; x++)
  139. {
  140. int offset = y * TWIDTH * TCOLS + x;
  141. int ok = 0;
  142. for(t = 0; t < 3; t++)
  143. {
  144. a = 2 * img1[offset * 4 + t];
  145. a += img1[(offset - TWIDTH * TCOLS - 1) * 4 + t];
  146. a += img1[(offset - TWIDTH * TCOLS) * 4 + t];
  147. a += img1[(offset - TWIDTH * TCOLS + 1) * 4 + t];
  148. a += img1[(offset - 1) * 4 + t];
  149. a += img1[(offset + 1) * 4 + t];
  150. a += img1[(offset + TWIDTH * TCOLS - 1) * 4 + t];
  151. a += img1[(offset + TWIDTH * TCOLS) * 4 + t];
  152. a += img1[(offset + TWIDTH * TCOLS + 1) * 4 + t];
  153. a /= 10;
  154. b = 2 * img2[offset * 4 + t];
  155. b += img2[(offset - TWIDTH * TCOLS - 1) * 4 + t];
  156. b += img2[(offset - TWIDTH * TCOLS) * 4 + t];
  157. b += img2[(offset - TWIDTH * TCOLS + 1) * 4 + t];
  158. b += img2[(offset - 1) * 4 + t];
  159. b += img2[(offset + 1) * 4 + t];
  160. b += img2[(offset + TWIDTH * TCOLS - 1) * 4 + t];
  161. b += img2[(offset + TWIDTH * TCOLS) * 4 + t];
  162. b += img2[(offset + TWIDTH * TCOLS + 1) * 4 + t];
  163. b /= 10;
  164. if(a < b - 8 || a > b + 8)
  165. {
  166. ok = 1;
  167. break;
  168. }
  169. }
  170. changed += ok;
  171. }
  172. return changed < (TWIDTH * THEIGHT * 10 / 100);
  173. }