suppressed memory leaks - added image conversion support if the codec does not suppor...
[ffmpeg.git] / output_example.c
1 /*
2  * Libavformat API example: Output a media file in any supported
3  * libavformat format. The default codecs are used.
4  * 
5  * Copyright (c) 2003 Fabrice Bellard
6  * 
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  * 
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  * 
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.  
24  */
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <math.h>
28
29 #include "avformat.h"
30
31 /* 5 seconds stream duration */
32 #define STREAM_DURATION 5.0
33
34
35 /**************************************************************/
36 /* audio output */
37
38 float t, tincr, tincr2;
39 int16_t *samples;
40 uint8_t *audio_outbuf;
41 int audio_outbuf_size;
42 int audio_input_frame_size;
43
44 /* 
45  * add an audio output stream
46  */
47 AVStream *add_audio_stream(AVFormatContext *oc, int codec_id)
48 {
49     AVCodecContext *c;
50     AVStream *st;
51
52     st = av_new_stream(oc, 1);
53     if (!st) {
54         fprintf(stderr, "Could not alloc stream\n");
55         exit(1);
56     }
57
58     c = &st->codec;
59     c->codec_id = codec_id;
60     c->codec_type = CODEC_TYPE_AUDIO;
61
62     /* put sample parameters */
63     c->bit_rate = 64000;
64     c->sample_rate = 44100;
65     c->channels = 2;
66     return st;
67 }
68
69 void open_audio(AVFormatContext *oc, AVStream *st)
70 {
71     AVCodecContext *c;
72     AVCodec *codec;
73
74     c = &st->codec;
75
76     /* find the audio encoder */
77     codec = avcodec_find_encoder(c->codec_id);
78     if (!codec) {
79         fprintf(stderr, "codec not found\n");
80         exit(1);
81     }
82
83     /* open it */
84     if (avcodec_open(c, codec) < 0) {
85         fprintf(stderr, "could not open codec\n");
86         exit(1);
87     }
88
89     /* init signal generator */
90     t = 0;
91     tincr = 2 * M_PI * 110.0 / c->sample_rate;
92     /* increment frequency by 110 Hz per second */
93     tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
94
95     audio_outbuf_size = 10000;
96     audio_outbuf = malloc(audio_outbuf_size);
97
98     /* ugly hack for PCM codecs (will be removed ASAP with new PCM
99        support to compute the input frame size in samples */
100     if (c->frame_size <= 1) {
101         audio_input_frame_size = audio_outbuf_size / c->channels;
102         switch(st->codec.codec_id) {
103         case CODEC_ID_PCM_S16LE:
104         case CODEC_ID_PCM_S16BE:
105         case CODEC_ID_PCM_U16LE:
106         case CODEC_ID_PCM_U16BE:
107             audio_input_frame_size >>= 1;
108             break;
109         default:
110             break;
111         }
112     } else {
113         audio_input_frame_size = c->frame_size;
114     }
115     samples = malloc(audio_input_frame_size * 2 * c->channels);
116 }
117
118 void write_audio_frame(AVFormatContext *oc, AVStream *st)
119 {
120     int j, out_size;
121     AVCodecContext *c;
122
123
124     c = &st->codec;
125
126     for(j=0;j<audio_input_frame_size;j++) {
127         samples[2*j] = (int)(sin(t) * 10000);
128         samples[2*j+1] = samples[2*j];
129         t += tincr;
130         tincr += tincr2;
131     }
132     
133     out_size = avcodec_encode_audio(c, audio_outbuf, audio_outbuf_size, samples);
134
135     /* write the compressed frame in the media file */
136     if (av_write_frame(oc, st->index, audio_outbuf, out_size) != 0) {
137         fprintf(stderr, "Error while writing audio frame\n");
138         exit(1);
139     }
140 }
141
142 void close_audio(AVFormatContext *oc, AVStream *st)
143 {
144     avcodec_close(&st->codec);
145     
146     av_free(samples);
147     av_free(audio_outbuf);
148 }
149
150 /**************************************************************/
151 /* video output */
152
153 AVFrame *picture, *tmp_picture;
154 uint8_t *video_outbuf;
155 int frame_count, video_outbuf_size;
156
157 /* add a video output stream */
158 AVStream *add_video_stream(AVFormatContext *oc, int codec_id)
159 {
160     AVCodecContext *c;
161     AVStream *st;
162
163     st = av_new_stream(oc, 0);
164     if (!st) {
165         fprintf(stderr, "Could not alloc stream\n");
166         exit(1);
167     }
168     
169     c = &st->codec;
170     c->codec_id = codec_id;
171     c->codec_type = CODEC_TYPE_VIDEO;
172
173     /* put sample parameters */
174     c->bit_rate = 400000;
175     /* resolution must be a multiple of two */
176     c->width = 352;  
177     c->height = 288;
178     /* frames per second */
179     c->frame_rate = 25;  
180     c->frame_rate_base= 1;
181     c->gop_size = 12; /* emit one intra frame every twelve frames */
182
183     return st;
184 }
185
186 AVFrame *alloc_picture(int pix_fmt, int width, int height)
187 {
188     AVFrame *picture;
189     uint8_t *picture_buf;
190     int size;
191     
192     picture = avcodec_alloc_frame();
193     if (!picture)
194         return NULL;
195     size = avpicture_get_size(pix_fmt, width, height);
196     picture_buf = malloc(size);
197     if (!picture_buf) {
198         av_free(picture);
199         return NULL;
200     }
201     avpicture_fill((AVPicture *)picture, picture_buf, 
202                    pix_fmt, width, height);
203     return picture;
204 }
205     
206 void open_video(AVFormatContext *oc, AVStream *st)
207 {
208     AVCodec *codec;
209     AVCodecContext *c;
210
211     c = &st->codec;
212
213     /* find the video encoder */
214     codec = avcodec_find_encoder(c->codec_id);
215     if (!codec) {
216         fprintf(stderr, "codec not found\n");
217         exit(1);
218     }
219
220     /* open the codec */
221     if (avcodec_open(c, codec) < 0) {
222         fprintf(stderr, "could not open codec\n");
223         exit(1);
224     }
225
226     video_outbuf = NULL;
227     if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
228         /* allocate output buffer */
229         /* XXX: API change will be done */
230         video_outbuf_size = 200000;
231         video_outbuf = malloc(video_outbuf_size);
232     }
233
234     /* allocate the encoded raw picture */
235     picture = alloc_picture(c->pix_fmt, c->width, c->height);
236     if (!picture) {
237         fprintf(stderr, "Could not allocate picture\n");
238         exit(1);
239     }
240
241     /* if the output format is not YUV420P, then a temporary YUV420P
242        picture is needed too. It is then converted to the required
243        output format */
244     tmp_picture = NULL;
245     if (c->pix_fmt != PIX_FMT_YUV420P) {
246         tmp_picture = alloc_picture(PIX_FMT_YUV420P, c->width, c->height);
247         if (!tmp_picture) {
248             fprintf(stderr, "Could not allocate temporary picture\n");
249             exit(1);
250         }
251     }
252 }
253
254 /* prepare a dummy image */
255 void fill_yuv_image(AVFrame *pict, int frame_index, int width, int height)
256 {
257     int x, y, i;
258
259     i = frame_index;
260
261     /* Y */
262     for(y=0;y<height;y++) {
263         for(x=0;x<width;x++) {
264             pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
265         }
266     }
267     
268     /* Cb and Cr */
269     for(y=0;y<height/2;y++) {
270         for(x=0;x<width/2;x++) {
271             pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
272             pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
273         }
274     }
275 }
276
277 void write_video_frame(AVFormatContext *oc, AVStream *st)
278 {
279     int out_size, ret;
280     AVCodecContext *c;
281
282     c = &st->codec;
283     
284     if (c->pix_fmt != PIX_FMT_YUV420P) {
285         /* as we only generate a YUV420P picture, we must convert it
286            to the codec pixel format if needed */
287         fill_yuv_image(tmp_picture, frame_count, c->width, c->height);
288         img_convert((AVPicture *)picture, c->pix_fmt, 
289                     (AVPicture *)tmp_picture, PIX_FMT_YUV420P,
290                     c->width, c->height);
291     } else {
292         fill_yuv_image(picture, frame_count, c->width, c->height);
293     }
294
295     
296     if (oc->oformat->flags & AVFMT_RAWPICTURE) {
297         /* raw video case. The API will change slightly in the near
298            futur for that */
299         ret = av_write_frame(oc, st->index, 
300                        (uint8_t *)picture, sizeof(AVPicture));
301     } else {
302         /* encode the image */
303         out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);
304         
305         /* write the compressed frame in the media file */
306         ret = av_write_frame(oc, st->index, video_outbuf, out_size);
307     }
308     if (ret != 0) {
309         fprintf(stderr, "Error while writing video frame\n");
310         exit(1);
311     }
312     frame_count++;
313 }
314
315 void close_video(AVFormatContext *oc, AVStream *st)
316 {
317     avcodec_close(&st->codec);
318     av_free(picture->data[0]);
319     av_free(picture);
320     if (tmp_picture) {
321         av_free(tmp_picture->data[0]);
322         av_free(tmp_picture);
323     }
324     av_free(video_outbuf);
325 }
326
327 /**************************************************************/
328 /* media file output */
329
330 int main(int argc, char **argv)
331 {
332     const char *filename;
333     AVOutputFormat *fmt;
334     AVFormatContext *oc;
335     AVStream *audio_st, *video_st;
336     double audio_pts, video_pts;
337     int i;
338
339     /* initialize libavcodec, and register all codecs and formats */
340     av_register_all();
341     
342     if (argc != 2) {
343         printf("usage: %s output_file\n"
344                "API example program to output a media file with libavformat.\n"
345                "The output format is automatically guessed according to the file extension.\n"
346                "Raw images can also be output by using '%%d' in the filename\n"
347                "\n", argv[0]);
348         exit(1);
349     }
350     
351     filename = argv[1];
352
353     /* auto detect the output format from the name. default is
354        mpeg. */
355     fmt = guess_format(NULL, filename, NULL);
356     if (!fmt) {
357         printf("Could not deduce output format from file extension: using MPEG.\n");
358         fmt = guess_format("mpeg", NULL, NULL);
359     }
360     if (!fmt) {
361         fprintf(stderr, "Could not find suitable output format\n");
362         exit(1);
363     }
364     
365     /* allocate the output media context */
366     oc = av_mallocz(sizeof(AVFormatContext));
367     if (!oc) {
368         fprintf(stderr, "Memory error\n");
369         exit(1);
370     }
371     oc->oformat = fmt;
372     snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
373
374     /* add the audio and video streams using the default format codecs
375        and initialize the codecs */
376     video_st = NULL;
377     audio_st = NULL;
378     if (fmt->video_codec != CODEC_ID_NONE) {
379         video_st = add_video_stream(oc, fmt->video_codec);
380     }
381     if (fmt->audio_codec != CODEC_ID_NONE) {
382         audio_st = add_audio_stream(oc, fmt->audio_codec);
383     }
384
385     /* set the output parameters (must be done even if no
386        parameters). */
387     if (av_set_parameters(oc, NULL) < 0) {
388         fprintf(stderr, "Invalid output format parameters\n");
389         exit(1);
390     }
391
392     dump_format(oc, 0, filename, 1);
393
394     /* now that all the parameters are set, we can open the audio and
395        video codecs and allocate the necessary encode buffers */
396     if (video_st)
397         open_video(oc, video_st);
398     if (audio_st)
399         open_audio(oc, audio_st);
400
401     /* open the output file, if needed */
402     if (!(fmt->flags & AVFMT_NOFILE)) {
403         if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) {
404             fprintf(stderr, "Could not open '%s'\n", filename);
405             exit(1);
406         }
407     }
408     
409     /* write the stream header, if any */
410     av_write_header(oc);
411     
412     for(;;) {
413         /* compute current audio and video time */
414         if (audio_st)
415             audio_pts = (double)audio_st->pts.val * oc->pts_num / oc->pts_den;
416         else
417             audio_pts = 0.0;
418         
419         if (video_st)
420             video_pts = (double)video_st->pts.val * oc->pts_num / oc->pts_den;
421         else
422             video_pts = 0.0;
423
424         if ((!audio_st || audio_pts >= STREAM_DURATION) && 
425             (!video_st || video_pts >= STREAM_DURATION))
426             break;
427         
428         /* write interleaved audio and video frames */
429         if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
430             write_audio_frame(oc, audio_st);
431         } else {
432             write_video_frame(oc, video_st);
433         }
434     }
435
436     /* close each codec */
437     if (video_st)
438         close_video(oc, video_st);
439     if (audio_st)
440         close_audio(oc, audio_st);
441
442     /* write the trailer, if any */
443     av_write_trailer(oc);
444     
445     /* free the streams */
446     for(i = 0; i < oc->nb_streams; i++) {
447         av_freep(&oc->streams[i]);
448     }
449
450     if (!(fmt->flags & AVFMT_NOFILE)) {
451         /* close the output file */
452         url_fclose(&oc->pb);
453     }
454
455     /* free the stream */
456     av_free(oc);
457
458     return 0;
459 }