00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <math.h>
00029
00030 #ifndef M_PI
00031 #define M_PI 3.14159265358979323846
00032 #endif
00033
00034 #include "avformat.h"
00035 #include "swscale.h"
00036
00037 #undef exit
00038
00039
00040 #define STREAM_DURATION 5.0
00041 #define STREAM_FRAME_RATE 25
00042 #define STREAM_NB_FRAMES ((int)(STREAM_DURATION * STREAM_FRAME_RATE))
00043 #define STREAM_PIX_FMT PIX_FMT_YUV420P
00044
00045 static int sws_flags = SWS_BICUBIC;
00046
00047
00048
00049
00050 float t, tincr, tincr2;
00051 int16_t *samples;
00052 uint8_t *audio_outbuf;
00053 int audio_outbuf_size;
00054 int audio_input_frame_size;
00055
00056
00057
00058
00059 static AVStream *add_audio_stream(AVFormatContext *oc, int codec_id)
00060 {
00061 AVCodecContext *c;
00062 AVStream *st;
00063
00064 st = av_new_stream(oc, 1);
00065 if (!st) {
00066 fprintf(stderr, "Could not alloc stream\n");
00067 exit(1);
00068 }
00069
00070 c = st->codec;
00071 c->codec_id = codec_id;
00072 c->codec_type = CODEC_TYPE_AUDIO;
00073
00074
00075 c->bit_rate = 64000;
00076 c->sample_rate = 44100;
00077 c->channels = 2;
00078 return st;
00079 }
00080
00081 static void open_audio(AVFormatContext *oc, AVStream *st)
00082 {
00083 AVCodecContext *c;
00084 AVCodec *codec;
00085
00086 c = st->codec;
00087
00088
00089 codec = avcodec_find_encoder(c->codec_id);
00090 if (!codec) {
00091 fprintf(stderr, "codec not found\n");
00092 exit(1);
00093 }
00094
00095
00096 if (avcodec_open(c, codec) < 0) {
00097 fprintf(stderr, "could not open codec\n");
00098 exit(1);
00099 }
00100
00101
00102 t = 0;
00103 tincr = 2 * M_PI * 110.0 / c->sample_rate;
00104
00105 tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
00106
00107 audio_outbuf_size = 10000;
00108 audio_outbuf = av_malloc(audio_outbuf_size);
00109
00110
00111
00112 if (c->frame_size <= 1) {
00113 audio_input_frame_size = audio_outbuf_size / c->channels;
00114 switch(st->codec->codec_id) {
00115 case CODEC_ID_PCM_S16LE:
00116 case CODEC_ID_PCM_S16BE:
00117 case CODEC_ID_PCM_U16LE:
00118 case CODEC_ID_PCM_U16BE:
00119 audio_input_frame_size >>= 1;
00120 break;
00121 default:
00122 break;
00123 }
00124 } else {
00125 audio_input_frame_size = c->frame_size;
00126 }
00127 samples = av_malloc(audio_input_frame_size * 2 * c->channels);
00128 }
00129
00130
00131
00132 static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels)
00133 {
00134 int j, i, v;
00135 int16_t *q;
00136
00137 q = samples;
00138 for(j=0;j<frame_size;j++) {
00139 v = (int)(sin(t) * 10000);
00140 for(i = 0; i < nb_channels; i++)
00141 *q++ = v;
00142 t += tincr;
00143 tincr += tincr2;
00144 }
00145 }
00146
00147 static void write_audio_frame(AVFormatContext *oc, AVStream *st)
00148 {
00149 AVCodecContext *c;
00150 AVPacket pkt;
00151 av_init_packet(&pkt);
00152
00153 c = st->codec;
00154
00155 get_audio_frame(samples, audio_input_frame_size, c->channels);
00156
00157 pkt.size= avcodec_encode_audio(c, audio_outbuf, audio_outbuf_size, samples);
00158
00159 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
00160 pkt.flags |= PKT_FLAG_KEY;
00161 pkt.stream_index= st->index;
00162 pkt.data= audio_outbuf;
00163
00164
00165 if (av_write_frame(oc, &pkt) != 0) {
00166 fprintf(stderr, "Error while writing audio frame\n");
00167 exit(1);
00168 }
00169 }
00170
00171 static void close_audio(AVFormatContext *oc, AVStream *st)
00172 {
00173 avcodec_close(st->codec);
00174
00175 av_free(samples);
00176 av_free(audio_outbuf);
00177 }
00178
00179
00180
00181
00182 AVFrame *picture, *tmp_picture;
00183 uint8_t *video_outbuf;
00184 int frame_count, video_outbuf_size;
00185
00186
00187 static AVStream *add_video_stream(AVFormatContext *oc, int codec_id)
00188 {
00189 AVCodecContext *c;
00190 AVStream *st;
00191
00192 st = av_new_stream(oc, 0);
00193 if (!st) {
00194 fprintf(stderr, "Could not alloc stream\n");
00195 exit(1);
00196 }
00197
00198 c = st->codec;
00199 c->codec_id = codec_id;
00200 c->codec_type = CODEC_TYPE_VIDEO;
00201
00202
00203 c->bit_rate = 400000;
00204
00205 c->width = 352;
00206 c->height = 288;
00207
00208
00209
00210
00211 c->time_base.den = STREAM_FRAME_RATE;
00212 c->time_base.num = 1;
00213 c->gop_size = 12;
00214 c->pix_fmt = STREAM_PIX_FMT;
00215 if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
00216
00217 c->max_b_frames = 2;
00218 }
00219 if (c->codec_id == CODEC_ID_MPEG1VIDEO){
00220
00221
00222
00223 c->mb_decision=2;
00224 }
00225
00226 if(!strcmp(oc->oformat->name, "mp4") || !strcmp(oc->oformat->name, "mov") || !strcmp(oc->oformat->name, "3gp"))
00227 c->flags |= CODEC_FLAG_GLOBAL_HEADER;
00228
00229 return st;
00230 }
00231
00232 static AVFrame *alloc_picture(int pix_fmt, int width, int height)
00233 {
00234 AVFrame *picture;
00235 uint8_t *picture_buf;
00236 int size;
00237
00238 picture = avcodec_alloc_frame();
00239 if (!picture)
00240 return NULL;
00241 size = avpicture_get_size(pix_fmt, width, height);
00242 picture_buf = av_malloc(size);
00243 if (!picture_buf) {
00244 av_free(picture);
00245 return NULL;
00246 }
00247 avpicture_fill((AVPicture *)picture, picture_buf,
00248 pix_fmt, width, height);
00249 return picture;
00250 }
00251
00252 static void open_video(AVFormatContext *oc, AVStream *st)
00253 {
00254 AVCodec *codec;
00255 AVCodecContext *c;
00256
00257 c = st->codec;
00258
00259
00260 codec = avcodec_find_encoder(c->codec_id);
00261 if (!codec) {
00262 fprintf(stderr, "codec not found\n");
00263 exit(1);
00264 }
00265
00266
00267 if (avcodec_open(c, codec) < 0) {
00268 fprintf(stderr, "could not open codec\n");
00269 exit(1);
00270 }
00271
00272 video_outbuf = NULL;
00273 if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
00274
00275
00276
00277
00278
00279
00280 video_outbuf_size = 200000;
00281 video_outbuf = av_malloc(video_outbuf_size);
00282 }
00283
00284
00285 picture = alloc_picture(c->pix_fmt, c->width, c->height);
00286 if (!picture) {
00287 fprintf(stderr, "Could not allocate picture\n");
00288 exit(1);
00289 }
00290
00291
00292
00293
00294 tmp_picture = NULL;
00295 if (c->pix_fmt != PIX_FMT_YUV420P) {
00296 tmp_picture = alloc_picture(PIX_FMT_YUV420P, c->width, c->height);
00297 if (!tmp_picture) {
00298 fprintf(stderr, "Could not allocate temporary picture\n");
00299 exit(1);
00300 }
00301 }
00302 }
00303
00304
00305 static void fill_yuv_image(AVFrame *pict, int frame_index, int width, int height)
00306 {
00307 int x, y, i;
00308
00309 i = frame_index;
00310
00311
00312 for(y=0;y<height;y++) {
00313 for(x=0;x<width;x++) {
00314 pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
00315 }
00316 }
00317
00318
00319 for(y=0;y<height/2;y++) {
00320 for(x=0;x<width/2;x++) {
00321 pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
00322 pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
00323 }
00324 }
00325 }
00326
00327 static void write_video_frame(AVFormatContext *oc, AVStream *st)
00328 {
00329 int out_size, ret;
00330 AVCodecContext *c;
00331 static struct SwsContext *img_convert_ctx;
00332
00333 c = st->codec;
00334
00335 if (frame_count >= STREAM_NB_FRAMES) {
00336
00337
00338
00339 } else {
00340 if (c->pix_fmt != PIX_FMT_YUV420P) {
00341
00342
00343 if (img_convert_ctx == NULL) {
00344 img_convert_ctx = sws_getContext(c->width, c->height,
00345 PIX_FMT_YUV420P,
00346 c->width, c->height,
00347 c->pix_fmt,
00348 sws_flags, NULL, NULL, NULL);
00349 if (img_convert_ctx == NULL) {
00350 fprintf(stderr, "Cannot initialize the conversion context\n");
00351 exit(1);
00352 }
00353 }
00354 fill_yuv_image(tmp_picture, frame_count, c->width, c->height);
00355 sws_scale(img_convert_ctx, tmp_picture->data, tmp_picture->linesize,
00356 0, c->height, picture->data, picture->linesize);
00357 } else {
00358 fill_yuv_image(picture, frame_count, c->width, c->height);
00359 }
00360 }
00361
00362
00363 if (oc->oformat->flags & AVFMT_RAWPICTURE) {
00364
00365
00366 AVPacket pkt;
00367 av_init_packet(&pkt);
00368
00369 pkt.flags |= PKT_FLAG_KEY;
00370 pkt.stream_index= st->index;
00371 pkt.data= (uint8_t *)picture;
00372 pkt.size= sizeof(AVPicture);
00373
00374 ret = av_write_frame(oc, &pkt);
00375 } else {
00376
00377 out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);
00378
00379 if (out_size > 0) {
00380 AVPacket pkt;
00381 av_init_packet(&pkt);
00382
00383 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
00384 if(c->coded_frame->key_frame)
00385 pkt.flags |= PKT_FLAG_KEY;
00386 pkt.stream_index= st->index;
00387 pkt.data= video_outbuf;
00388 pkt.size= out_size;
00389
00390
00391 ret = av_write_frame(oc, &pkt);
00392 } else {
00393 ret = 0;
00394 }
00395 }
00396 if (ret != 0) {
00397 fprintf(stderr, "Error while writing video frame\n");
00398 exit(1);
00399 }
00400 frame_count++;
00401 }
00402
00403 static void close_video(AVFormatContext *oc, AVStream *st)
00404 {
00405 avcodec_close(st->codec);
00406 av_free(picture->data[0]);
00407 av_free(picture);
00408 if (tmp_picture) {
00409 av_free(tmp_picture->data[0]);
00410 av_free(tmp_picture);
00411 }
00412 av_free(video_outbuf);
00413 }
00414
00415
00416
00417
00418 int main(int argc, char **argv)
00419 {
00420 const char *filename;
00421 AVOutputFormat *fmt;
00422 AVFormatContext *oc;
00423 AVStream *audio_st, *video_st;
00424 double audio_pts, video_pts;
00425 int i;
00426
00427
00428 av_register_all();
00429
00430 if (argc != 2) {
00431 printf("usage: %s output_file\n"
00432 "API example program to output a media file with libavformat.\n"
00433 "The output format is automatically guessed according to the file extension.\n"
00434 "Raw images can also be output by using '%%d' in the filename\n"
00435 "\n", argv[0]);
00436 exit(1);
00437 }
00438
00439 filename = argv[1];
00440
00441
00442
00443 fmt = guess_format(NULL, filename, NULL);
00444 if (!fmt) {
00445 printf("Could not deduce output format from file extension: using MPEG.\n");
00446 fmt = guess_format("mpeg", NULL, NULL);
00447 }
00448 if (!fmt) {
00449 fprintf(stderr, "Could not find suitable output format\n");
00450 exit(1);
00451 }
00452
00453
00454 oc = av_alloc_format_context();
00455 if (!oc) {
00456 fprintf(stderr, "Memory error\n");
00457 exit(1);
00458 }
00459 oc->oformat = fmt;
00460 snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
00461
00462
00463
00464 video_st = NULL;
00465 audio_st = NULL;
00466 if (fmt->video_codec != CODEC_ID_NONE) {
00467 video_st = add_video_stream(oc, fmt->video_codec);
00468 }
00469 if (fmt->audio_codec != CODEC_ID_NONE) {
00470 audio_st = add_audio_stream(oc, fmt->audio_codec);
00471 }
00472
00473
00474
00475 if (av_set_parameters(oc, NULL) < 0) {
00476 fprintf(stderr, "Invalid output format parameters\n");
00477 exit(1);
00478 }
00479
00480 dump_format(oc, 0, filename, 1);
00481
00482
00483
00484 if (video_st)
00485 open_video(oc, video_st);
00486 if (audio_st)
00487 open_audio(oc, audio_st);
00488
00489
00490 if (!(fmt->flags & AVFMT_NOFILE)) {
00491 if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) {
00492 fprintf(stderr, "Could not open '%s'\n", filename);
00493 exit(1);
00494 }
00495 }
00496
00497
00498 av_write_header(oc);
00499
00500 for(;;) {
00501
00502 if (audio_st)
00503 audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;
00504 else
00505 audio_pts = 0.0;
00506
00507 if (video_st)
00508 video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den;
00509 else
00510 video_pts = 0.0;
00511
00512 if ((!audio_st || audio_pts >= STREAM_DURATION) &&
00513 (!video_st || video_pts >= STREAM_DURATION))
00514 break;
00515
00516
00517 if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
00518 write_audio_frame(oc, audio_st);
00519 } else {
00520 write_video_frame(oc, video_st);
00521 }
00522 }
00523
00524
00525 if (video_st)
00526 close_video(oc, video_st);
00527 if (audio_st)
00528 close_audio(oc, audio_st);
00529
00530
00531 av_write_trailer(oc);
00532
00533
00534 for(i = 0; i < oc->nb_streams; i++) {
00535 av_freep(&oc->streams[i]->codec);
00536 av_freep(&oc->streams[i]);
00537 }
00538
00539 if (!(fmt->flags & AVFMT_NOFILE)) {
00540
00541 url_fclose(oc->pb);
00542 }
00543
00544
00545 av_free(oc);
00546
00547 return 0;
00548 }