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

Last change on this file since 4736 was 4736, checked in by Sam Hocevar, 10 years ago

Only use first stream in the storyboard code.

File size: 7.4 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 <libavcodec/avcodec.h>
22#include <libavformat/avformat.h>
23#include <libswscale/swscale.h>
24
25#include <pipi.h>
26
27#define STEP 12
28
29#define TWIDTH 90
30#define THEIGHT 60
31#define TCOLS 10
32#define TROWS 50
33#define NTHUMBS (TCOLS*TROWS)
34
35static int similar(uint8_t *img1, uint8_t *img2);
36static void decorate(uint8_t *img);
37
38int main(int argc, char *argv[])
39{
40    char fmtstr[1024];
41    AVPacket packet;
42    AVFormatContext *fmt;
43    AVCodecContext *ctx;
44    AVCodec *codec;
45    AVFrame *frame;
46    struct SwsContext *sws = NULL;
47    pipi_image_t *image;
48    pipi_pixels_t *p;
49    uint8_t *buffer;
50    char *parser;
51    int stream, i, n = 0, k = 0, idx = 0;
52
53    if(argc < 2)
54        return EXIT_FAILURE;
55
56    parser = strrchr(argv[1], '/');
57    strcpy(fmtstr, parser ? parser + 1 : argv[1]);
58    parser = strrchr(fmtstr, '.');
59    if(parser)
60        *parser = '\0';
61    strcat(fmtstr, ".t%02i.jpeg");
62
63    image = pipi_new(TWIDTH * TCOLS, THEIGHT * TROWS);
64    p = pipi_get_pixels(image, PIPI_PIXELS_RGBA_U8);
65    buffer = (uint8_t *)p->pixels;
66
67    av_register_all();
68    if(av_open_input_file(&fmt, argv[1], NULL, 0, NULL) != 0)
69        return EXIT_FAILURE;
70    if(av_find_stream_info(fmt) < 0 )
71        return EXIT_FAILURE;
72
73    stream = -1;
74    for(i = 0; stream == -1 && i < (int)fmt->nb_streams; i++)
75        if(fmt->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
76        {
77            stream = i;
78            break;
79        }
80    if(stream == -1)
81        return EXIT_FAILURE;
82    ctx = fmt->streams[stream]->codec;
83
84    codec = avcodec_find_decoder(ctx->codec_id);
85    if(codec == NULL)
86        return EXIT_FAILURE;
87    if(avcodec_open(ctx, codec) < 0)
88        return EXIT_FAILURE;
89
90    frame = avcodec_alloc_frame();
91
92    for(;;)
93    {
94        int finished, ret;
95
96        ret = av_read_frame(fmt, &packet);
97
98        if(idx == NTHUMBS || (idx > 0 && ret < 0))
99        {
100            char buf[1024];
101            sprintf(buf, fmtstr, k++);
102            printf("saving %i thumbs in %s\n", idx, buf);
103            pipi_save(image, buf);
104            memset(buffer, 0, TWIDTH * TCOLS * THEIGHT * TROWS * 4);
105            idx = 0;
106        }
107
108        if(ret < 0)
109            break;
110
111        if(packet.stream_index != stream)
112        {
113            av_free_packet(&packet);
114            continue;
115        }
116
117        avcodec_decode_video(ctx, frame, &finished, packet.data, packet.size);
118        if(!finished)
119        {
120            av_free_packet(&packet);
121            continue;
122        }
123
124        /* Only process every 20th image */
125        if((++n % STEP) == STEP / 2)
126        {
127            uint8_t *start;
128            int pitch = TWIDTH * TCOLS * 4;
129            int good = 1;
130
131            start = buffer + (idx % TCOLS) * TWIDTH * 4
132                           + (idx / TCOLS) * TWIDTH * TCOLS * 4 * THEIGHT;
133
134            if(!sws)
135                sws = sws_getContext(ctx->width, ctx->height, ctx->pix_fmt,
136                                     TWIDTH, THEIGHT, PIX_FMT_RGB32,
137                                     SWS_BICUBIC, NULL, NULL, NULL);
138
139            sws_scale(sws, (uint8_t const **)frame->data, frame->linesize, 0,
140                      ctx->height, &start, &pitch);
141
142            decorate(start);
143
144            if(idx > 0)
145            {
146                uint8_t *prev;
147
148                if(idx % TCOLS)
149                    prev = start - TWIDTH * 4;
150                else
151                    prev = start + (TCOLS - 1) * TWIDTH * 4
152                                 - TWIDTH * TCOLS * 4 * THEIGHT;
153
154                /* Now check whether the new image is really different
155                 * from the previous one (> 10% pixel changes) */
156                if(similar(start, prev))
157                    good = 0;
158            }
159
160            if(good)
161            {
162                idx++;
163            }
164        }
165
166        av_free_packet(&packet);
167    }
168
169    return EXIT_SUCCESS;
170}
171
172static int similar(uint8_t *img1, uint8_t *img2)
173{
174    int x, y, t, a, b, changed = 0;
175
176    for(y = 2; y < THEIGHT - 2; y++)
177        for(x = 2; x < TWIDTH - 2; x++)
178        {
179            int offset = y * TWIDTH * TCOLS + x;
180            int ok = 0;
181
182            for(t = 0; t < 3; t++)
183            {
184                a = 2 * img1[offset * 4 + t];
185                a += img1[(offset - TWIDTH * TCOLS - 1) * 4 + t];
186                a += img1[(offset - TWIDTH * TCOLS) * 4 + t];
187                a += img1[(offset - TWIDTH * TCOLS + 1) * 4 + t];
188                a += img1[(offset - 1) * 4 + t];
189                a += img1[(offset + 1) * 4 + t];
190                a += img1[(offset + TWIDTH * TCOLS - 1) * 4 + t];
191                a += img1[(offset + TWIDTH * TCOLS) * 4 + t];
192                a += img1[(offset + TWIDTH * TCOLS + 1) * 4 + t];
193                a /= 10;
194
195                b = 2 * img2[offset * 4 + t];
196                b += img2[(offset - TWIDTH * TCOLS - 1) * 4 + t];
197                b += img2[(offset - TWIDTH * TCOLS) * 4 + t];
198                b += img2[(offset - TWIDTH * TCOLS + 1) * 4 + t];
199                b += img2[(offset - 1) * 4 + t];
200                b += img2[(offset + 1) * 4 + t];
201                b += img2[(offset + TWIDTH * TCOLS - 1) * 4 + t];
202                b += img2[(offset + TWIDTH * TCOLS) * 4 + t];
203                b += img2[(offset + TWIDTH * TCOLS + 1) * 4 + t];
204                b /= 10;
205
206                if(a < b - 8 || a > b + 8)
207                {
208                    ok = 1;
209                    break;
210                }
211            }
212
213            changed += ok;
214        }
215
216    return changed < (TWIDTH * THEIGHT * 10 / 100);
217}
218
219static void decorate(uint8_t *img)
220{
221    static int const hi = 200;
222    static int const lo = 50;
223    static int const mid = 127;
224    int x, y;
225
226    for(y = 0; y < THEIGHT; y++)
227    {
228        img[(y * TWIDTH * TCOLS) * 4] = hi;
229        img[(y * TWIDTH * TCOLS) * 4 + 1] = hi;
230        img[(y * TWIDTH * TCOLS) * 4 + 2] = hi;
231        img[(y * TWIDTH * TCOLS + TWIDTH - 1) * 4] = lo;
232        img[(y * TWIDTH * TCOLS + TWIDTH - 1) * 4 + 1] = lo;
233        img[(y * TWIDTH * TCOLS + TWIDTH - 1) * 4 + 2] = lo;
234    }
235
236    for(x = 0; x < TWIDTH; x++)
237    {
238        img[x * 4] = hi;
239        img[x * 4 + 1] = hi;
240        img[x * 4 + 2] = hi;
241        img[((THEIGHT - 1) * TWIDTH * TCOLS + x) * 4] = lo;
242        img[((THEIGHT - 1) * TWIDTH * TCOLS + x) * 4 + 1] = lo;
243        img[((THEIGHT - 1) * TWIDTH * TCOLS + x) * 4 + 2] = lo;
244    }
245
246    img[0] = (mid + hi) / 2;
247    img[1] = (mid + hi) / 2;
248    img[2] = (mid + hi) / 2;
249
250    img[(TWIDTH - 1) * 4 + 0] = mid;
251    img[(TWIDTH - 1) * 4 + 1] = mid;
252    img[(TWIDTH - 1) * 4 + 2] = mid;
253
254    img[((THEIGHT - 1) * TWIDTH * TCOLS) * 4 + 0] = mid;
255    img[((THEIGHT - 1) * TWIDTH * TCOLS) * 4 + 1] = mid;
256    img[((THEIGHT - 1) * TWIDTH * TCOLS) * 4 + 2] = mid;
257
258    img[((THEIGHT - 1) * TWIDTH * TCOLS + TWIDTH - 1) * 4 + 0] = (mid + lo) / 2;
259    img[((THEIGHT - 1) * TWIDTH * TCOLS + TWIDTH - 1) * 4 + 1] = (mid + lo) / 2;
260    img[((THEIGHT - 1) * TWIDTH * TCOLS + TWIDTH - 1) * 4 + 2] = (mid + lo) / 2;
261}
262
Note: See TracBrowser for help on using the repository browser.