Advertisement
Guest User

Untitled

a guest
Jun 19th, 2013
342
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.29 KB | None | 0 0
  1. /*
  2.  *
  3.  * SAMPLE CODE FOR MP4-to-MPEG-TS CONTAINER CONVERSION
  4.  *
  5.  * This is the basis for a python plugin for doing on-the-fly segmentation of
  6.  *
  7.  *
  8.  */
  9.  
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13.  
  14. #include <libavformat/avformat.h>
  15. #include <libavutil/mathematics.h>  // For av_rescale_q
  16.  
  17. typedef struct
  18. {
  19.     const char *input_filename;
  20.     const char *output_playlist;
  21.     const char *output_prefix;
  22.     double segment_length;
  23. } config_info;
  24.  
  25. typedef struct
  26. {
  27.     double duration;
  28.     char *filename;
  29. } segment_info;
  30.  
  31. static AVStream *add_output_stream(AVFormatContext *output_format_context, AVStream *input_stream)
  32. {
  33.     AVCodecContext *input_codec_context;
  34.     AVCodecContext *output_codec_context;
  35.     AVStream *output_stream;
  36.  
  37.     output_stream = avformat_new_stream(output_format_context, NULL);
  38.     if (!output_stream) {
  39.         fprintf(stderr, "Could not allocate stream\n");
  40.         exit(1);
  41.     }
  42.  
  43.     input_codec_context = input_stream->codec;
  44.     output_codec_context = output_stream->codec;
  45.  
  46.     output_codec_context->codec_id = input_codec_context->codec_id;
  47.     output_codec_context->codec_type = input_codec_context->codec_type;
  48.     output_codec_context->codec_tag = input_codec_context->codec_tag;
  49.     output_codec_context->bit_rate = input_codec_context->bit_rate;
  50.     output_codec_context->extradata = input_codec_context->extradata;
  51.     output_codec_context->extradata_size = input_codec_context->extradata_size;
  52.  
  53.     // Some codecs put the wrong ticks_per_frame in (in the thousands instead of tens)
  54.     if(av_q2d(input_codec_context->time_base) * input_codec_context->ticks_per_frame > av_q2d(input_stream->time_base) && av_q2d(input_stream->time_base) < 1.0/1000) {
  55.         output_codec_context->time_base = input_codec_context->time_base;
  56.         output_codec_context->time_base.num *= input_codec_context->ticks_per_frame;
  57.     }
  58.     else {
  59.         output_codec_context->time_base = input_stream->time_base;
  60.     }
  61.  
  62.     switch (input_codec_context->codec_type) {
  63.         case AVMEDIA_TYPE_AUDIO:
  64.             output_codec_context->channel_layout = input_codec_context->channel_layout;
  65.             output_codec_context->sample_rate = input_codec_context->sample_rate;
  66.             output_codec_context->channels = input_codec_context->channels;
  67.             output_codec_context->frame_size = input_codec_context->frame_size;
  68.             if ((input_codec_context->block_align == 1 && input_codec_context->codec_id == AV_CODEC_ID_MP3) || input_codec_context->codec_id == AV_CODEC_ID_AC3) {
  69.                 output_codec_context->block_align = 0;
  70.             }
  71.             else {
  72.                 output_codec_context->block_align = input_codec_context->block_align;
  73.             }
  74.             fprintf(stdout, "Audio time bases:\n");
  75.             break;
  76.         case AVMEDIA_TYPE_VIDEO:
  77.             output_codec_context->pix_fmt = input_codec_context->pix_fmt;
  78.             output_codec_context->width = input_codec_context->width;
  79.             output_codec_context->height = input_codec_context->height;
  80.             output_codec_context->has_b_frames = input_codec_context->has_b_frames;
  81.  
  82.             if (output_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
  83.                 output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
  84.             }
  85.             fprintf(stdout, "Video time bases:\n");
  86.             break;
  87.         default:
  88.             break;
  89.     }
  90.  
  91.     return output_stream;
  92. }
  93.  
  94. static int write_frame_fixed(AVPacket *packet, AVFormatContext *input_context, AVFormatContext *output_context, AVBitStreamFilterContext *bsf)
  95. {
  96.     int si = packet->stream_index;
  97.     if (output_context->streams[si]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  98.     {
  99.         if (input_context->streams[si]->codec->codec_id == AV_CODEC_ID_H264)
  100.         {
  101.             int a = av_bitstream_filter_filter(bsf, output_context->streams[si]->codec, NULL,
  102.                                                &packet->data, &packet->size,
  103.                                                packet->data, packet->size,
  104.                                                packet->flags & AV_PKT_FLAG_KEY);
  105.  
  106.             if (a == 0)
  107.             {
  108.                 fprintf(stderr, "Eh?!\n");
  109.             }
  110.             else if (a < 0)
  111.             {
  112.                 fprintf(stderr, "%s failed for stream %d, codec %s, error %d\n", bsf->filter->name, packet->stream_index, output_context->streams[si]->codec->codec->name, a);
  113.                 exit(1);
  114.             }
  115.         }
  116.     }
  117.  
  118.     packet->pts = av_rescale_q(packet->pts, input_context->streams[si]->time_base, output_context->streams[si]->time_base);
  119.     packet->dts = av_rescale_q(packet->dts, input_context->streams[si]->time_base, output_context->streams[si]->time_base);
  120.  
  121.     return av_interleaved_write_frame(output_context, packet);
  122. }
  123.  
  124. int main(int argc, char **argv)
  125. {
  126.     if (argc != 5)
  127.     {
  128.         fprintf(stderr, "Usage: %s <input filename> <playlist filename> <output prefix> <segment length>\n", argv[0]);
  129.         exit(1);
  130.     }
  131.  
  132.     config_info config;
  133.     memset(&config, 0, sizeof(config_info));
  134.  
  135.     config.input_filename = argv[1];
  136.     config.output_playlist = argv[2];
  137.     config.output_prefix = argv[3];
  138.     config.segment_length = atoi(argv[4]);
  139.  
  140.     printf("Segment length: %f", config.segment_length);
  141.  
  142.     char *output_filename = (char*) malloc(sizeof(char) * (strlen(config.output_prefix) + 10));
  143.     if (!output_filename)
  144.     {
  145.         fprintf(stderr, "Segmenter error: Could not allocate space for output filenames with prefix %s\n", config.output_prefix);
  146.         exit(1);
  147.     }
  148.  
  149.     avcodec_register_all();
  150.     av_register_all();
  151.  
  152.     // Start context from file, guess format type based on filename
  153.     AVFormatContext *input_context = NULL;
  154.     int ret = avformat_open_input(&input_context, config.input_filename, NULL, NULL);
  155.     if (ret != 0)
  156.     {
  157.         fprintf(stderr, "Segmenter error: Could not open input file, make sure it is an MP4 file: %d\n", ret);
  158.         exit(1);
  159.     }
  160.  
  161.     if (avformat_find_stream_info(input_context, NULL) < 0)
  162.     {
  163.         fprintf(stderr, "Segmenter error Could not read stream information.\n");
  164.         exit(1);
  165.     }
  166.  
  167.     AVOutputFormat *output_format = av_guess_format("mpegts", NULL, NULL);
  168.     if (!output_format)
  169.     {
  170.         fprintf(stderr, "Segmenter error: Could not find MPEG-TS muxer.\n");
  171.         exit(1);
  172.     }
  173.  
  174.     AVFormatContext *output_context = avformat_alloc_context();
  175.     if (!output_context)
  176.     {
  177.         fprintf(stderr, "Segmenter error: Could not allocate output context.\n");
  178.         exit(1);
  179.     }
  180.     output_context->oformat = output_format;
  181.  
  182.     int video_index = -1;
  183.     int audio_index = -1;
  184.  
  185.     AVStream *video_stream;
  186.     AVStream *audio_stream;
  187.  
  188.     int i;
  189.  
  190.     for (i = 0; i < input_context->nb_streams && (video_index < 0 || audio_index < 0); i++)
  191.     {
  192.         switch (input_context->streams[i]->codec->codec_type)
  193.         {
  194.             case AVMEDIA_TYPE_VIDEO:
  195.                 video_index = i;
  196.                 input_context->streams[i]->discard = AVDISCARD_NONE;
  197.                 video_stream = add_output_stream(output_context, input_context->streams[i]);
  198.                 break;
  199.  
  200.             case AVMEDIA_TYPE_AUDIO:
  201.                 audio_index = i;
  202.                 input_context->streams[i]->discard = AVDISCARD_NONE;
  203.                 audio_stream = add_output_stream(output_context, input_context->streams[i]);
  204.                 break;
  205.  
  206.             default:
  207.                 input_context->streams[i]->discard = AVDISCARD_ALL;
  208.                 break;
  209.         }
  210.     }
  211.  
  212.     if (video_index == -1 || audio_index == -1)
  213.     {
  214.         fprintf(stderr, "Segmenter error: Video or audio stream not found.\n");
  215.         exit(1);
  216.     }
  217.  
  218.     av_dump_format(input_context, 0, config.input_filename, 0);
  219.     av_dump_format(output_context, 0, config.output_prefix, 1);
  220.  
  221.     AVCodec *codec = avcodec_find_decoder(video_stream->codec->codec_id);
  222.     if (!codec)
  223.     {
  224.         fprintf(stderr, "Segmenter error: Could not find video decoder, key frames will not be honored.\n");
  225.     }
  226.  
  227.     if (avcodec_open2(video_stream->codec, codec, NULL) < 0)
  228.     {
  229.         fprintf(stderr, "Segmenter error: Could not open video decoder, key frames will not be honored.\n");
  230.     }
  231.  
  232.     AVCodec *codec2 = avcodec_find_decoder(audio_stream->codec->codec_id);
  233.     if (!codec2)
  234.     {
  235.         fprintf(stderr, "Segmenter error: Could not find audio decoder, key frames will not be honored.\n");
  236.     }
  237.  
  238.     if (avcodec_open2(audio_stream->codec, codec2, NULL) < 0)
  239.     {
  240.         fprintf(stderr, "Segmenter error: Could not open audio decoder, key frames will not be honored.\n");
  241.     }
  242.  
  243.     // Generate output filename
  244.     unsigned int output_index = 1;
  245.     snprintf(output_filename, strlen(config.output_prefix) + 10, "%s-%05u.ts", config.output_prefix, output_index++);
  246.  
  247.     if (avio_open(&output_context->pb, output_filename, AVIO_FLAG_WRITE) < 0)
  248.     {
  249.         fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename);
  250.         exit(1);
  251.     }
  252.  
  253.  
  254.     if (avformat_write_header(output_context, NULL))
  255.     {
  256.         fprintf(stderr, "Segmenter error: Could not write mpegts header to first output file.\n");
  257.         exit(1);
  258.     }
  259.  
  260.     // Required when muxing h264 into MPEG-TS
  261.     AVBitStreamFilterContext *bsf = av_bitstream_filter_init("h264_mp4toannexb");
  262.     if (!bsf)
  263.     {
  264.         fprintf(stderr, "Error initializing the h264_mp4toannexb filter!");
  265.         exit(1);
  266.     }
  267.  
  268.     double prev_segment_time = 0;
  269.     int decode_done;
  270.     int packet_c = 0;
  271.     int64_t ppts = 0;
  272.     double tbase;
  273.  
  274.     av_seek_frame(input_context, video_index, seek_to , 0);
  275.     do
  276.     {
  277.         double segment_time;
  278.         AVPacket packet;
  279.         av_init_packet(&packet);
  280.         decode_done = av_read_frame(input_context, &packet);
  281.         if (decode_done < 0)
  282.         {
  283.             break;
  284.         }
  285.  
  286.         if (av_dup_packet(&packet) < 0)
  287.         {
  288.             fprintf(stderr, "Segmenter error: Could not duplicate packet (av_dup_packet).\n");
  289.             av_free_packet(&packet);
  290.             break;
  291.         }
  292.  
  293.         ppts = packet.pts;
  294.         tbase = av_q2d(input_context->streams[packet.stream_index]->time_base);
  295.  
  296.         if (prev_segment_time == 0)
  297.         {
  298.             prev_segment_time = ppts * tbase;
  299.         }
  300.  
  301.         // Segmentation time!
  302.         if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY))
  303.         {
  304.             segment_time = ppts * tbase;
  305.             //printf("Video keyframe at %f\n", segment_time);
  306.         }
  307.         else
  308.         {
  309.             segment_time = prev_segment_time;
  310.         }
  311.  
  312.         if (segment_time - prev_segment_time >= config.segment_length)
  313.         {
  314.             fprintf(stdout, "Segment from %f to %f (%f seconds, %d packets).\n", prev_segment_time, segment_time, (segment_time - prev_segment_time), packet_c);
  315.             avio_flush(output_context->pb);
  316.             avio_close(output_context->pb);
  317.  
  318.             packet_c = 0;
  319.  
  320.             snprintf(output_filename, strlen(config.output_prefix) + 10, "%s-%05u.ts", config.output_prefix, output_index++);
  321.             if (avio_open(&output_context->pb, output_filename, AVIO_FLAG_WRITE) < 0)
  322.             {
  323.                 fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename);
  324.                 exit(1);
  325.             }
  326.  
  327.             prev_segment_time = segment_time;
  328.         }
  329.         ret = write_frame_fixed(&packet, input_context, output_context, bsf);
  330.         packet_c++;
  331.         if (ret < 0)
  332.         {
  333.             fprintf(stderr, "Segmenter error: Could not write frame of stream: %d\n", ret);
  334.             exit(1);
  335.         }
  336.         else if (ret > 0)
  337.         {
  338.             fprintf(stderr, "Segmenter info: End of stream requested.\n");
  339.             av_free_packet(&packet);
  340.             break;
  341.         }
  342.         av_free_packet(&packet);
  343.     } while (!decode_done);
  344.  
  345.     av_write_trailer(output_context);
  346.     avcodec_close(video_stream->codec);
  347.  
  348.     for (i = 0; i < output_context->nb_streams; i++)
  349.     {
  350.         av_freep(&output_context->streams[i]->codec);
  351.         av_freep(&output_context->streams[i]);
  352.     }
  353.  
  354.     av_bitstream_filter_close(bsf);
  355.  
  356.     avio_close(output_context->pb);
  357.     av_free(output_context);
  358.  
  359.     fprintf(stdout, "SUCCESS!!!\n");
  360.     exit(0);
  361. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement