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.
 
 
 
 
 
 

185 line
4.7 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 20
  23. #define TWIDTH 90
  24. #define THEIGHT 60
  25. #define TCOLS 10
  26. #define TROWS 200
  27. #define NTHUMBS (TCOLS*TROWS)
  28. int main(int argc, char *argv[])
  29. {
  30. char fmtstr[1024];
  31. AVPacket packet;
  32. AVFormatContext *fmt;
  33. AVCodecContext *ctx;
  34. AVCodec *codec;
  35. AVFrame *frame;
  36. struct SwsContext *sws;
  37. pipi_image_t *image;
  38. pipi_pixels_t *p;
  39. uint8_t *buffer;
  40. char *parser;
  41. int stream, i, n = 0, k = 0, idx = 0;
  42. if(argc < 2)
  43. return EXIT_FAILURE;
  44. strcpy(fmtstr, argv[1]);
  45. parser = strrchr(fmtstr, '.');
  46. if(parser)
  47. strcpy(parser, "%03i.jpeg");
  48. else
  49. strcat(fmtstr, "%03i.jpeg");
  50. image = pipi_new(TWIDTH * TCOLS, THEIGHT * TROWS);
  51. p = pipi_get_pixels(image, PIPI_PIXELS_RGBA_U8);
  52. buffer = (uint8_t *)p->pixels;
  53. av_register_all();
  54. if(av_open_input_file(&fmt, argv[1], NULL, 0, NULL) != 0)
  55. return EXIT_FAILURE;
  56. if(av_find_stream_info(fmt) < 0 )
  57. return EXIT_FAILURE;
  58. stream = -1;
  59. for(i = 0; stream == -1 && i < (int)fmt->nb_streams; i++)
  60. if(fmt->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
  61. stream = i;
  62. if(stream == -1)
  63. return EXIT_FAILURE;
  64. ctx = fmt->streams[stream]->codec;
  65. codec = avcodec_find_decoder(ctx->codec_id);
  66. if(codec == NULL)
  67. return EXIT_FAILURE;
  68. if(avcodec_open(ctx, codec) < 0)
  69. return EXIT_FAILURE;
  70. frame = avcodec_alloc_frame();
  71. sws = sws_getContext(ctx->width, ctx->height, ctx->pix_fmt,
  72. TWIDTH, THEIGHT, PIX_FMT_RGB32,
  73. SWS_BICUBIC, NULL, NULL, NULL);
  74. for(;;)
  75. {
  76. int finished, ret;
  77. ret = av_read_frame(fmt, &packet);
  78. if(idx == NTHUMBS || (idx > 0 && ret < 0))
  79. {
  80. /* Only process every 20th image */
  81. char buf[1024];
  82. sprintf(buf, fmtstr, k++);
  83. printf("saving %i thumbs in %s\n", idx, buf);
  84. pipi_save(image, buf);
  85. memset(buffer, 0, TWIDTH * TCOLS * THEIGHT * TROWS * 4);
  86. idx = 0;
  87. }
  88. if(ret < 0)
  89. break;
  90. if(packet.stream_index != stream)
  91. {
  92. av_free_packet(&packet);
  93. continue;
  94. }
  95. avcodec_decode_video(ctx, frame, &finished, packet.data, packet.size);
  96. if(!finished)
  97. {
  98. av_free_packet(&packet);
  99. continue;
  100. }
  101. n++;
  102. if((n % STEP) == STEP / 2)
  103. {
  104. int pitch = TWIDTH * TCOLS * 4;
  105. uint8_t *start;
  106. start = buffer + (idx % TCOLS) * TWIDTH * 4
  107. + (idx / TCOLS) * TWIDTH * TCOLS * 4 * THEIGHT;
  108. sws_scale(sws, frame->data, frame->linesize, 0, ctx->height,
  109. &start, &pitch);
  110. /* Now check whether the new image is really different
  111. * from the previous one (> 8% pixel changes) */
  112. if(idx == 0)
  113. {
  114. idx++;
  115. }
  116. else
  117. {
  118. uint8_t *prev;
  119. int x, y, t, a, b, changed = 0;
  120. if(idx % TCOLS)
  121. prev = start - TWIDTH * 4;
  122. else
  123. prev = start + (TCOLS - 1) * TWIDTH * 4
  124. - TWIDTH * TCOLS * 4 * THEIGHT;
  125. for(y = 0; y < THEIGHT; y++)
  126. for(x = 0; x < TWIDTH; x++)
  127. {
  128. int ok = 0;
  129. for(t = 0; t < 3; t++)
  130. {
  131. int offset = y * TWIDTH * TCOLS + x;
  132. a = start[offset * 4 + t];
  133. b = prev[offset * 4 + t];
  134. if(a < b - 5 || a > b + 5)
  135. {
  136. ok = 1;
  137. break;
  138. }
  139. }
  140. changed += ok;
  141. }
  142. if(changed > TWIDTH * THEIGHT * 8 / 100)
  143. idx++;
  144. }
  145. }
  146. av_free_packet(&packet);
  147. }
  148. return EXIT_SUCCESS;
  149. }