1 | /* |
---|
2 | * dumpmovie dump a movie into YUV PNG files |
---|
3 | * Copyright (c) 2010 Sam Hocevar <sam@hocevar.net> |
---|
4 | * All Rights Reserved |
---|
5 | * |
---|
6 | * $Id: dumpmovie.c 4880 2014-06-13 05:41:12Z sam $ |
---|
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 | int main(int argc, char *argv[]) |
---|
28 | { |
---|
29 | char fmtstr[1024]; |
---|
30 | AVPacket packet; |
---|
31 | AVFormatContext *fmt; |
---|
32 | AVCodecContext *ctx; |
---|
33 | AVCodec *codec; |
---|
34 | AVFrame *frame; |
---|
35 | struct SwsContext *sws = NULL; |
---|
36 | pipi_image_t *image = NULL; |
---|
37 | pipi_pixels_t *p; |
---|
38 | uint8_t *dst[4], *data = NULL; |
---|
39 | char *parser; |
---|
40 | int stream, pitch[4], i, k = 0, nframes = -1; |
---|
41 | double skip_seconds = 0.0; |
---|
42 | |
---|
43 | if (argc < 2) |
---|
44 | return EXIT_FAILURE; |
---|
45 | |
---|
46 | if (argc > 2) |
---|
47 | skip_seconds = atof(argv[2]); |
---|
48 | if (argc > 3) |
---|
49 | nframes = atoi(argv[3]); |
---|
50 | |
---|
51 | /* Ensure our linear YUV values do not get gamma-corrected */ |
---|
52 | pipi_set_gamma(1.0); |
---|
53 | |
---|
54 | parser = strrchr(argv[1], '/'); |
---|
55 | strcpy(fmtstr, parser ? parser + 1 : argv[1]); |
---|
56 | parser = strrchr(fmtstr, '.'); |
---|
57 | if(parser) |
---|
58 | *parser = '\0'; |
---|
59 | strcat(fmtstr, "-%06i.png"); |
---|
60 | |
---|
61 | av_register_all(); |
---|
62 | if(av_open_input_file(&fmt, argv[1], NULL, 0, NULL) != 0) |
---|
63 | return EXIT_FAILURE; |
---|
64 | if(av_find_stream_info(fmt) < 0 ) |
---|
65 | return EXIT_FAILURE; |
---|
66 | |
---|
67 | stream = -1; |
---|
68 | for(i = 0; stream == -1 && i < (int)fmt->nb_streams; i++) |
---|
69 | if(fmt->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) |
---|
70 | stream = i; |
---|
71 | if(stream == -1) |
---|
72 | return EXIT_FAILURE; |
---|
73 | ctx = fmt->streams[stream]->codec; |
---|
74 | |
---|
75 | codec = avcodec_find_decoder(ctx->codec_id); |
---|
76 | if(codec == NULL) |
---|
77 | return EXIT_FAILURE; |
---|
78 | if(avcodec_open(ctx, codec) < 0) |
---|
79 | return EXIT_FAILURE; |
---|
80 | |
---|
81 | skip_seconds /= av_q2d(fmt->streams[stream]->time_base); |
---|
82 | av_seek_frame(fmt, stream, (int)(skip_seconds + 0.5), SEEK_SET); |
---|
83 | //avformat_seek_file(fmt, stream, skip_bytes, skip_bytes, |
---|
84 | // skip_bytes, AVSEEK_FLAG_BYTE); |
---|
85 | |
---|
86 | frame = avcodec_alloc_frame(); |
---|
87 | |
---|
88 | for (k = 0; k < nframes || nframes == -1; /* k incremented below */) |
---|
89 | { |
---|
90 | int finished, ret, x, y; |
---|
91 | |
---|
92 | ret = av_read_frame(fmt, &packet); |
---|
93 | |
---|
94 | if(ret < 0) |
---|
95 | break; |
---|
96 | |
---|
97 | if(packet.stream_index != stream) |
---|
98 | { |
---|
99 | av_free_packet(&packet); |
---|
100 | continue; |
---|
101 | } |
---|
102 | |
---|
103 | avcodec_decode_video2(ctx, frame, &finished, packet.data, packet.size); |
---|
104 | if(!finished) |
---|
105 | { |
---|
106 | av_free_packet(&packet); |
---|
107 | continue; |
---|
108 | } |
---|
109 | |
---|
110 | if(!sws) |
---|
111 | { |
---|
112 | sws = sws_getContext(ctx->width, ctx->height, ctx->pix_fmt, |
---|
113 | ctx->width, ctx->height, PIX_FMT_YUV444P, |
---|
114 | SWS_FAST_BILINEAR, NULL, NULL, NULL); |
---|
115 | pitch[0] = ctx->width; |
---|
116 | pitch[1] = ctx->width; |
---|
117 | pitch[2] = ctx->width; |
---|
118 | pitch[3] = 0; |
---|
119 | dst[0] = malloc(ctx->width * ctx->height * 3); |
---|
120 | dst[1] = dst[0] + ctx->width * ctx->height; |
---|
121 | dst[2] = dst[1] + ctx->width * ctx->height; |
---|
122 | dst[3] = NULL; |
---|
123 | image = pipi_new(ctx->width, ctx->height); |
---|
124 | } |
---|
125 | |
---|
126 | { |
---|
127 | char buf[1024]; |
---|
128 | sprintf(buf, fmtstr, k); |
---|
129 | printf("saving in %s\n", buf); |
---|
130 | |
---|
131 | sws_scale(sws, (uint8_t const **)frame->data, frame->linesize, 0, |
---|
132 | ctx->height, dst, pitch); |
---|
133 | |
---|
134 | p = pipi_get_pixels(image, PIPI_PIXELS_RGBA_U8); |
---|
135 | data = (uint8_t *)p->pixels; |
---|
136 | |
---|
137 | for (y = 0; y < ctx->height; y++) |
---|
138 | { |
---|
139 | int off = y * ctx->width; |
---|
140 | |
---|
141 | for (x = 0; x < ctx->width; x++, off++) |
---|
142 | { |
---|
143 | /* Reorder components to store YUVA */ |
---|
144 | data[4 * off] = dst[0][off]; |
---|
145 | data[4 * off + 1] = dst[2][off]; |
---|
146 | data[4 * off + 2] = dst[1][off]; |
---|
147 | data[4 * off + 3] = 0xff; |
---|
148 | } |
---|
149 | } |
---|
150 | |
---|
151 | pipi_save(image, buf); |
---|
152 | } |
---|
153 | |
---|
154 | av_free_packet(&packet); |
---|
155 | |
---|
156 | k++; |
---|
157 | } |
---|
158 | |
---|
159 | return EXIT_SUCCESS; |
---|
160 | } |
---|
161 | |
---|