|
- /*
- * storyboard generate a storyboard from a movie
- * Copyright (c) 2009 Sam Hocevar <sam@zoy.org>
- * All Rights Reserved
- *
- * $Id$
- *
- * This program is free software. It comes without any warranty, to
- * the extent permitted by applicable law. You can redistribute it
- * and/or modify it under the terms of the Do What The Fuck You Want
- * To Public License, Version 2, as published by Sam Hocevar. See
- * http://sam.zoy.org/wtfpl/COPYING for more details.
- */
-
- #include "config.h"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include <avcodec.h>
- #include <avformat.h>
- #include <swscale.h>
-
- #include <pipi.h>
-
- #define STEP 20
-
- #define TWIDTH 90
- #define THEIGHT 60
- #define TCOLS 10
- #define TROWS 200
- #define NTHUMBS (TCOLS*TROWS)
-
- int main(int argc, char *argv[])
- {
- char fmtstr[1024];
- AVPacket packet;
- AVFormatContext *fmt;
- AVCodecContext *ctx;
- AVCodec *codec;
- AVFrame *frame;
- struct SwsContext *sws;
- pipi_image_t *image;
- pipi_pixels_t *p;
- uint8_t *buffer;
- char *parser;
- int stream, i, n = 0, k = 0, idx = 0;
-
- if(argc < 2)
- return EXIT_FAILURE;
-
- strcpy(fmtstr, argv[1]);
- parser = strrchr(fmtstr, '.');
- if(parser)
- strcpy(parser, "%03i.jpeg");
- else
- strcat(fmtstr, "%03i.jpeg");
-
- image = pipi_new(TWIDTH * TCOLS, THEIGHT * TROWS);
- p = pipi_get_pixels(image, PIPI_PIXELS_RGBA_U8);
- buffer = (uint8_t *)p->pixels;
-
- av_register_all();
- if(av_open_input_file(&fmt, argv[1], NULL, 0, NULL) != 0)
- return EXIT_FAILURE;
- if(av_find_stream_info(fmt) < 0 )
- return EXIT_FAILURE;
-
- stream = -1;
- for(i = 0; stream == -1 && i < (int)fmt->nb_streams; i++)
- if(fmt->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
- stream = i;
- if(stream == -1)
- return EXIT_FAILURE;
- ctx = fmt->streams[stream]->codec;
-
- codec = avcodec_find_decoder(ctx->codec_id);
- if(codec == NULL)
- return EXIT_FAILURE;
- if(avcodec_open(ctx, codec) < 0)
- return EXIT_FAILURE;
-
- frame = avcodec_alloc_frame();
-
- sws = sws_getContext(ctx->width, ctx->height, ctx->pix_fmt,
- TWIDTH, THEIGHT, PIX_FMT_RGB32,
- SWS_BICUBIC, NULL, NULL, NULL);
-
- for(;;)
- {
- int finished, ret;
-
- ret = av_read_frame(fmt, &packet);
-
- if(idx == NTHUMBS || (idx > 0 && ret < 0))
- {
- /* Only process every 20th image */
- char buf[1024];
- sprintf(buf, fmtstr, k++);
- printf("saving %i thumbs in %s\n", idx, buf);
- pipi_save(image, buf);
- memset(buffer, 0, TWIDTH * TCOLS * THEIGHT * TROWS * 4);
- idx = 0;
- }
-
- if(ret < 0)
- break;
-
- if(packet.stream_index != stream)
- {
- av_free_packet(&packet);
- continue;
- }
-
- avcodec_decode_video(ctx, frame, &finished, packet.data, packet.size);
- if(!finished)
- {
- av_free_packet(&packet);
- continue;
- }
-
- n++;
-
- if((n % STEP) == STEP / 2)
- {
- int pitch = TWIDTH * TCOLS * 4;
- uint8_t *start;
-
- start = buffer + (idx % TCOLS) * TWIDTH * 4
- + (idx / TCOLS) * TWIDTH * TCOLS * 4 * THEIGHT;
-
- sws_scale(sws, frame->data, frame->linesize, 0, ctx->height,
- &start, &pitch);
-
- /* Now check whether the new image is really different
- * from the previous one (> 8% pixel changes) */
- if(idx == 0)
- {
- idx++;
- }
- else
- {
- uint8_t *prev;
- int x, y, t, a, b, changed = 0;
-
- if(idx % TCOLS)
- prev = start - TWIDTH * 4;
- else
- prev = start + (TCOLS - 1) * TWIDTH * 4
- - TWIDTH * TCOLS * 4 * THEIGHT;
-
- for(y = 0; y < THEIGHT; y++)
- for(x = 0; x < TWIDTH; x++)
- {
- int ok = 0;
-
- for(t = 0; t < 3; t++)
- {
- int offset = y * TWIDTH * TCOLS + x;
- a = start[offset * 4 + t];
- b = prev[offset * 4 + t];
-
- if(a < b - 5 || a > b + 5)
- {
- ok = 1;
- break;
- }
- }
-
- changed += ok;
- }
-
- if(changed > TWIDTH * THEIGHT * 8 / 100)
- idx++;
- }
- }
-
- av_free_packet(&packet);
- }
-
- return EXIT_SUCCESS;
- }
|