Advertisement
Guest User

C mp4 to mpeg2-ts

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