Merge commit 'f78d360bba6dcfb585847a49a84e89c25950fbdb'
[ffmpeg.git] / doc / examples / decode_video.c
1 /*
2  * Copyright (c) 2001 Fabrice Bellard
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22
23 /**
24  * @file
25  * video decoding with libavcodec API example
26  *
27  * @example decode_video.c
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <libavcodec/avcodec.h>
35
36 #define INBUF_SIZE 4096
37
38 static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
39                      char *filename)
40 {
41     FILE *f;
42     int i;
43
44     f = fopen(filename,"w");
45     fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
46     for (i = 0; i < ysize; i++)
47         fwrite(buf + i * wrap, 1, xsize, f);
48     fclose(f);
49 }
50
51 static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt,
52                    const char *filename)
53 {
54     char buf[1024];
55     int ret, got_picture;
56
57     while (pkt->size > 0) {
58         ret = avcodec_decode_video2(dec_ctx, frame, &got_picture, pkt);
59         if (ret < 0) {
60             fprintf(stderr, "Error while decoding frame %d\n", dec_ctx->frame_number);
61             exit(1);
62         }
63         if (got_picture) {
64             printf("saving frame %3d\n", dec_ctx->frame_number);
65             fflush(stdout);
66
67             /* the picture is allocated by the decoder. no need to
68                free it */
69             snprintf(buf, sizeof(buf), filename, dec_ctx->frame_number);
70             pgm_save(frame->data[0], frame->linesize[0],
71                      frame->width, frame->height, buf);
72         }
73         if (pkt->data) {
74             pkt->size -= ret;
75             pkt->data += ret;
76         }
77     }
78 }
79
80 int main(int argc, char **argv)
81 {
82     const char *filename, *outfilename;
83     const AVCodec *codec;
84     AVCodecParserContext *parser;
85     AVCodecContext *c= NULL;
86     FILE *f;
87     AVFrame *frame;
88     uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
89     uint8_t *data;
90     size_t   data_size;
91     int ret;
92     AVPacket avpkt;
93
94     if (argc <= 2) {
95         fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
96         exit(0);
97     }
98     filename    = argv[1];
99     outfilename = argv[2];
100
101     avcodec_register_all();
102
103     av_init_packet(&avpkt);
104
105     /* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
106     memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
107
108     /* find the MPEG-1 video decoder */
109     codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);
110     if (!codec) {
111         fprintf(stderr, "Codec not found\n");
112         exit(1);
113     }
114
115     parser = av_parser_init(codec->id);
116     if (!parser) {
117         fprintf(stderr, "parser not found\n");
118         exit(1);
119     }
120
121     c = avcodec_alloc_context3(codec);
122     if (!c) {
123         fprintf(stderr, "Could not allocate video codec context\n");
124         exit(1);
125     }
126
127     /* For some codecs, such as msmpeg4 and mpeg4, width and height
128        MUST be initialized there because this information is not
129        available in the bitstream. */
130
131     /* open it */
132     if (avcodec_open2(c, codec, NULL) < 0) {
133         fprintf(stderr, "Could not open codec\n");
134         exit(1);
135     }
136
137     f = fopen(filename, "rb");
138     if (!f) {
139         fprintf(stderr, "Could not open %s\n", filename);
140         exit(1);
141     }
142
143     frame = av_frame_alloc();
144     if (!frame) {
145         fprintf(stderr, "Could not allocate video frame\n");
146         exit(1);
147     }
148
149     while (!feof(f)) {
150         /* read raw data from the input file */
151         data_size = fread(inbuf, 1, INBUF_SIZE, f);
152         if (!data_size)
153             break;
154
155         /* use the parser to split the data into frames */
156         data = inbuf;
157         while (data_size > 0) {
158             ret = av_parser_parse2(parser, c, &avpkt.data, &avpkt.size,
159                                    data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
160             if (ret < 0) {
161                 fprintf(stderr, "Error while parsing\n");
162                 exit(1);
163             }
164             data      += ret;
165             data_size -= ret;
166
167             if (avpkt.size)
168                 decode(c, frame, &avpkt, outfilename);
169          }
170      }
171
172     /* flush the decoder */
173     avpkt.data = NULL;
174     avpkt.size = 0;
175     decode(c, frame, &avpkt, outfilename);
176
177     fclose(f);
178
179     av_parser_close(parser);
180     avcodec_free_context(&c);
181     av_frame_free(&frame);
182
183     return 0;
184 }