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