Advertisement
Guest User

Untitled

a guest
Feb 22nd, 2017
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.15 KB | None | 0 0
  1.  
  2. #define STREAM_DURATION   10.0
  3. #define STREAM_FRAME_RATE 25 /* 25 images/s */
  4. #define STREAM_PIX_FMT    AV_PIX_FMT_YUV420P /* default pix_fmt */
  5. #define SCALE_FLAGS SWS_BICUBIC
  6.  
  7.  
  8. extern "C"
  9. {
  10.     #include <libavutil/opt.h>
  11.     #include <libavcodec/avcodec.h>
  12.     #include <libavformat/avformat.h>
  13.     #include <libavutil/imgutils.h>
  14.     #include <libswscale/swscale.h>
  15.  
  16.  
  17.  
  18. #include <libavutil/avassert.h>
  19. #include <libavutil/channel_layout.h>
  20. #include <libavutil/opt.h>
  21. #include <libavutil/mathematics.h>
  22. //#include <libavutil/timestamp.h>
  23. #include <libavformat/avformat.h>
  24. #include <libswscale/swscale.h>
  25. #include <libswresample/swresample.h>
  26. }
  27.  
  28.  
  29. // a wrapper around a single output AVStream
  30. typedef struct OutputStream {
  31.     AVStream *st;
  32.     AVCodecContext *enc;
  33.  
  34.     /* pts of the next frame that will be generated */
  35.     int64_t next_pts;
  36.     int samples_count;
  37.  
  38.     AVFrame *frame;
  39.     AVFrame *tmp_frame;
  40.  
  41.     float t, tincr, tincr2;
  42.  
  43.     struct SwsContext *sws_ctx;
  44.     struct SwrContext *swr_ctx;
  45. } OutputStream;
  46.  
  47. static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt)
  48. {
  49.     AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
  50.  
  51. //    printf("pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
  52. //           av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
  53. //           av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
  54. //           av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
  55. //           pkt->stream_index);
  56. }
  57.  
  58. static int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
  59. {
  60.     /* rescale output packet timestamp values from codec to stream timebase */
  61.     av_packet_rescale_ts(pkt, *time_base, st->time_base);
  62.     pkt->stream_index = st->index;
  63.  
  64.     /* Write the compressed frame to the media file. */
  65.     log_packet(fmt_ctx, pkt);
  66.     return av_interleaved_write_frame(fmt_ctx, pkt);
  67. }
  68.  
  69. /* Add an output stream. */
  70. static void add_stream(OutputStream *ost, AVFormatContext *oc,
  71.                        AVCodec **codec,
  72.                        enum AVCodecID codec_id)
  73. {
  74.     AVCodecContext *c;
  75.     int i;
  76.  
  77.     /* find the encoder */
  78.     *codec = avcodec_find_encoder(codec_id);
  79.     if (!(*codec)) {
  80.         fprintf(stderr, "Could not find encoder for '%s'\n",
  81.                 avcodec_get_name(codec_id));
  82.         exit(1);
  83.     }
  84.  
  85.     ost->st = avformat_new_stream(oc, NULL);
  86.     if (!ost->st) {
  87.         fprintf(stderr, "Could not allocate stream\n");
  88.         exit(1);
  89.     }
  90.     ost->st->id = oc->nb_streams-1;
  91.     c = avcodec_alloc_context3(*codec);
  92.     if (!c) {
  93.         fprintf(stderr, "Could not alloc an encoding context\n");
  94.         exit(1);
  95.     }
  96.     ost->enc = c;
  97.  
  98.     c->codec_id = codec_id;
  99.  
  100.     /* put sample parameters */
  101.     //c->bit_rate = 400000;
  102.     /* resolution must be a multiple of two */
  103.     c->width    = 352;
  104.     c->height   = 288;
  105.     /* frames per second */
  106.     AVRational sr;
  107.     sr.num = 1;
  108.     sr.den = 25;
  109.     c->time_base = sr;
  110.     /* emit one intra frame every ten frames
  111.      * check frame pict_type before passing frame
  112.      * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
  113.      * then gop_size is ignored and the output of encoder
  114.      * will always be I frame irrespective to gop_size
  115.      */
  116.     c->gop_size = 10;
  117.     c->max_b_frames = 1;
  118.     c->pix_fmt = AV_PIX_FMT_YUV420P;
  119.  
  120.     //if (codec_id == AV_CODEC_ID_HEVC)
  121.         av_opt_set(c->priv_data, "preset", "medium", 0);
  122.  
  123.     /* ---- */
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.     /* Some formats want stream headers to be separate. */
  132. //    if (oc->oformat->flags & AVFMT_GLOBALHEADER)
  133. //        c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  134. }
  135.  
  136. /**************************************************************/
  137. /* video output */
  138.  
  139. static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
  140. {
  141.     AVFrame *picture;
  142.     int ret;
  143.  
  144.     picture = av_frame_alloc();
  145.     if (!picture)
  146.         return NULL;
  147.  
  148.     picture->format = pix_fmt;
  149.     picture->width  = width;
  150.     picture->height = height;
  151.  
  152.     /* allocate the buffers for the frame data */
  153.     ret = av_frame_get_buffer(picture, 32);
  154.     if (ret < 0) {
  155.         fprintf(stderr, "Could not allocate frame data.\n");
  156.         exit(1);
  157.     }
  158.  
  159.     return picture;
  160. }
  161.  
  162. static void open_video(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg)
  163. {
  164.     int ret;
  165.     AVCodecContext *c = ost->enc;
  166.     AVDictionary *opt = NULL;
  167.  
  168.     av_dict_copy(&opt, opt_arg, 0);
  169.  
  170.     /* open the codec */
  171.     ret = avcodec_open2(c, codec, &opt);
  172.     av_dict_free(&opt);
  173.     if (ret < 0) {
  174.         qDebug() << "Could not open vide codec";
  175. //        fprintf(stderr, "Could not open video codec: %s\n", av_err2str(ret));
  176.         exit(1);
  177.     }
  178.  
  179.     printf("CODED: %s\n", codec->name);
  180.  
  181.     /* allocate and init a re-usable frame */
  182.     ost->frame = alloc_picture(c->pix_fmt, c->width, c->height);
  183.     if (!ost->frame) {
  184.         fprintf(stderr, "Could not allocate video frame\n");
  185.         exit(1);
  186.     }
  187.  
  188.     /* If the output format is not YUV420P, then a temporary YUV420P
  189.      * picture is needed too. It is then converted to the required
  190.      * output format. */
  191.     ost->tmp_frame = NULL;
  192.     if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
  193.         ost->tmp_frame = alloc_picture(AV_PIX_FMT_YUV420P, c->width, c->height);
  194.         if (!ost->tmp_frame) {
  195.             fprintf(stderr, "Could not allocate temporary picture\n");
  196.             exit(1);
  197.         }
  198.     }
  199.  
  200.     /* copy the stream parameters to the muxer */
  201.     ret = avcodec_parameters_from_context(ost->st->codecpar, c);
  202.     if (ret < 0) {
  203.         fprintf(stderr, "Could not copy the stream parameters\n");
  204.         exit(1);
  205.     }
  206. }
  207.  
  208. /* Prepare a dummy image. */
  209. static void fill_yuv_image(AVFrame *pict, int frame_index,
  210.                            int width, int height)
  211. {
  212.     int x, y, i, ret;
  213.  
  214.     /* when we pass a frame to the encoder, it may keep a reference to it
  215.      * internally;
  216.      * make sure we do not overwrite it here
  217.      */
  218.     ret = av_frame_make_writable(pict);
  219.     if (ret < 0)
  220.         exit(1);
  221.  
  222.     i = frame_index;
  223.  
  224.     /* Y */
  225.     for (y = 0; y < height; y++)
  226.         for (x = 0; x < width; x++)
  227.             pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
  228.  
  229.     /* Cb and Cr */
  230.     for (y = 0; y < height / 2; y++) {
  231.         for (x = 0; x < width / 2; x++) {
  232.             pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
  233.             pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
  234.         }
  235.     }
  236. }
  237.  
  238. static AVFrame *get_video_frame(OutputStream *ost)
  239. {
  240.     AVCodecContext *c = ost->enc;
  241.  
  242.     /* check if we want to generate more frames */
  243.     AVRational sr;
  244.     sr.num = sr.den = 1;
  245.     if (av_compare_ts(ost->next_pts, c->time_base,
  246.                       STREAM_DURATION, sr) >= 0)
  247.         return NULL;
  248.  
  249.     if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
  250.         /* as we only generate a YUV420P picture, we must convert it
  251.          * to the codec pixel format if needed */
  252.         if (!ost->sws_ctx) {
  253.             ost->sws_ctx = sws_getContext(c->width, c->height,
  254.                                           AV_PIX_FMT_YUV420P,
  255.                                           c->width, c->height,
  256.                                           c->pix_fmt,
  257.                                           SCALE_FLAGS, NULL, NULL, NULL);
  258.             if (!ost->sws_ctx) {
  259.                 fprintf(stderr,
  260.                         "Could not initialize the conversion context\n");
  261.                 exit(1);
  262.             }
  263.         }
  264.         fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height);
  265.         sws_scale(ost->sws_ctx,
  266.                   (const uint8_t * const *)ost->tmp_frame->data, ost->tmp_frame->linesize,
  267.                   0, c->height, ost->frame->data, ost->frame->linesize);
  268.     } else {
  269.         fill_yuv_image(ost->frame, ost->next_pts, c->width, c->height);
  270.     }
  271.  
  272.     ost->frame->pts = ost->next_pts++;
  273.  
  274.     return ost->frame;
  275. }
  276.  
  277. /*
  278.  * encode one video frame and send it to the muxer
  279.  * return 1 when encoding is finished, 0 otherwise
  280.  */
  281. static int write_video_frame(AVFormatContext *oc, OutputStream *ost)
  282. {
  283.     int ret;
  284.     AVCodecContext *c;
  285.     AVFrame *frame;
  286.     int got_packet = 0;
  287.     AVPacket pkt = { 0 };
  288.  
  289.     c = ost->enc;
  290.  
  291.     frame = get_video_frame(ost);
  292.  
  293.     av_init_packet(&pkt);
  294.  
  295.     /* encode the image */
  296.     ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
  297.     if (ret < 0) {
  298.         qDebug() << "error encoding frame";
  299. //        fprintf(stderr, "Error encoding video frame: %s\n", av_err2str(ret));
  300.         exit(1);
  301.     }
  302.  
  303.     if (got_packet) {
  304.         ret = write_frame(oc, &c->time_base, ost->st, &pkt);
  305.     } else {
  306.         ret = 0;
  307.     }
  308.  
  309.     if (ret < 0) {
  310.         qDebug() << "error writing frame";
  311. //        fprintf(stderr, "Error while writing video frame: %s\n", av_err2str(ret));
  312.         exit(1);
  313.     }
  314.  
  315.     return (frame || got_packet) ? 0 : 1;
  316. }
  317.  
  318. static void close_stream(AVFormatContext *oc, OutputStream *ost)
  319. {
  320.     avcodec_free_context(&ost->enc);
  321.     av_frame_free(&ost->frame);
  322.     av_frame_free(&ost->tmp_frame);
  323.     sws_freeContext(ost->sws_ctx);
  324.     //swr_free(&ost->swr_ctx);
  325. }
  326.  
  327. /**************************************************************/
  328. /* media file output */
  329.  
  330. int ffmain(int argc, char **argv)
  331. {
  332.     OutputStream video_st = { 0 }, audio_st = { 0 };
  333.     const char *filename;
  334.     AVOutputFormat *fmt;
  335.     AVFormatContext *oc = NULL;
  336.     AVCodec *audio_codec, *video_codec;
  337.     int ret;
  338.     int have_video = 0, have_audio = 0;
  339.     int encode_video = 0, encode_audio = 0;
  340.     AVDictionary *opt = NULL;
  341.     int i;
  342.  
  343.     /* Initialize libavcodec, and register all codecs and formats. */
  344.     av_register_all();
  345.  
  346.     if (argc < 2) {
  347.         printf("usage: %s output_file\n"
  348.                "API example program to output a media file with libavformat.\n"
  349.                "This program generates a synthetic audio and video stream, encodes and\n"
  350.                "muxes them into a file named output_file.\n"
  351.                "The output format is automatically guessed according to the file extension.\n"
  352.                "Raw images can also be output by using '%%d' in the filename.\n"
  353.                "\n", argv[0]);
  354.         return 1;
  355.     }
  356.  
  357.     filename = argv[1];
  358.     for (i = 2; i+1 < argc; i+=2) {
  359.         if (!strcmp(argv[i], "-flags") || !strcmp(argv[i], "-fflags"))
  360.             av_dict_set(&opt, argv[i]+1, argv[i+1], 0);
  361.         printf("opt: \"%s\" to \"%s\"\n", argv[i]+1, argv[i+1]);
  362.         fflush(stdout);
  363.     }
  364.  
  365.     /* allocate the output media context */
  366.     avformat_alloc_output_context2(&oc, NULL, NULL, filename);
  367.     if (!oc) {
  368.         printf("Could not deduce output format from file extension: using MPEG.\n");
  369.         avformat_alloc_output_context2(&oc, NULL, "mpeg", filename);
  370.     }
  371.     if (!oc)
  372.         return 1;
  373.  
  374.     oc->oformat->video_codec = AV_CODEC_ID_HEVC;
  375.  
  376.     fmt = oc->oformat;
  377.  
  378.     /* Add the audio and video streams using the default format codecs
  379.      * and initialize the codecs. */
  380.     if (fmt->video_codec != AV_CODEC_ID_NONE) {
  381.         add_stream(&video_st, oc, &video_codec, fmt->video_codec);
  382.         have_video = 1;
  383.         encode_video = 1;
  384.     }
  385.  
  386.     /* Now that all the parameters are set, we can open the audio and
  387.      * video codecs and allocate the necessary encode buffers. */
  388.     if (have_video)
  389.         open_video(oc, video_codec, &video_st, opt);
  390.  
  391.     av_dump_format(oc, 0, filename, 1);
  392.  
  393.     /* open the output file, if needed */
  394.     if (!(fmt->flags & AVFMT_NOFILE)) {
  395.         ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
  396.         if (ret < 0)
  397.         {
  398.             qDebug() << "Could not open blabla";
  399. //            fprintf(stderr, "Could not open '%s': %s\n", filename,
  400. //                    av_err2str(ret));
  401.             return 1;
  402.         }
  403.     }
  404.  
  405.     /* Write the stream header, if any. */
  406.     ret = avformat_write_header(oc, &opt);
  407.     if (ret < 0) {
  408.         qDebug() << "Could not write header";
  409. //        fprintf(stderr, "Error occurred when opening output file: %s\n",
  410. //                av_err2str(ret));
  411.         return 1;
  412.     }
  413.  
  414.     while (encode_video || encode_audio) {
  415.         /* select the stream to encode */
  416.         if (encode_video &&
  417.             (!encode_audio || av_compare_ts(video_st.next_pts, video_st.enc->time_base,
  418.                                             audio_st.next_pts, audio_st.enc->time_base) <= 0)) {
  419.             encode_video = !write_video_frame(oc, &video_st);
  420.         }
  421.     }
  422.  
  423.     /* Write the trailer, if any. The trailer must be written before you
  424.      * close the CodecContexts open when you wrote the header; otherwise
  425.      * av_write_trailer() may try to use memory that was freed on
  426.      * av_codec_close(). */
  427.     av_write_trailer(oc);
  428.  
  429.     /* Close each codec. */
  430.     if (have_video)
  431.         close_stream(oc, &video_st);
  432.     if (have_audio)
  433.         close_stream(oc, &audio_st);
  434.  
  435.     if (!(fmt->flags & AVFMT_NOFILE))
  436.         /* Close the output file. */
  437.         avio_closep(&oc->pb);
  438.  
  439.     /* free the stream */
  440.     avformat_free_context(oc);
  441.  
  442.     return 0;
  443. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement