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