source: libpipi/trunk/examples/storyboard.c @ 3345

Last change on this file since 3345 was 3345, checked in by Sam Hocevar, 12 years ago

Added a movie thumbnailer (storyboard generator) using libavcodec.

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