Browse Source

Added a movie thumbnailer (storyboard generator) using libavcodec.

git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@3345 92316355-f0b4-4df1-b90c-862c8a59935f
master
sam 16 years ago
parent
commit
70e7f92416
2 changed files with 191 additions and 1 deletions
  1. +7
    -1
      examples/Makefile.am
  2. +184
    -0
      examples/storyboard.c

+ 7
- 1
examples/Makefile.am View File

@@ -3,7 +3,7 @@
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/pipi -I../pipi

noinst_PROGRAMS = edd img2rubik sharpen floodfill line bezier histogram \
colorstring
colorstring storyboard

edd_SOURCES = edd.c
edd_LDADD = ../pipi/libpipi.la
@@ -28,3 +28,9 @@ histogram_LDADD = ../pipi/libpipi.la

colorstring_SOURCES = colorstring.c
colorstring_LDADD = ../pipi/libpipi.la

storyboard_SOURCES = storyboard.c
storyboard_LDADD = ../pipi/libpipi.la
storyboard_CFLAGS = `pkg-config --cflags libavformat libavcodec libswscale`
storyboard_LDFLAGS = `pkg-config --libs libavformat libavcodec libswscale`


+ 184
- 0
examples/storyboard.c View File

@@ -0,0 +1,184 @@
/*
* 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;
}


Loading…
Cancel
Save