Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- *
- * SAMPLE CODE FOR MP4-to-MPEG-TS CONTAINER CONVERSION
- *
- * This is the basis for a python plugin for doing on-the-fly segmentation of
- *
- *
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <libavformat/avformat.h>
- typedef struct config_info
- {
- const char *input_filename;
- const char *output_playlist;
- const char *output_prefix;
- int segment_length;
- } config_info;
- static AVStream *add_output_stream(AVFormatContext *output_format_context, AVStream *input_stream)
- {
- AVCodecContext *input_codec_context;
- AVCodecContext *output_codec_context;
- AVStream *output_stream;
- output_stream = avformat_new_stream(output_format_context, NULL);
- if (!output_stream) {
- fprintf(stderr, "Could not allocate stream\n");
- exit(1);
- }
- input_codec_context = input_stream->codec;
- output_codec_context = output_stream->codec;
- output_codec_context->codec_id = input_codec_context->codec_id;
- output_codec_context->codec_type = input_codec_context->codec_type;
- output_codec_context->codec_tag = input_codec_context->codec_tag;
- output_codec_context->bit_rate = input_codec_context->bit_rate;
- output_codec_context->extradata = input_codec_context->extradata;
- output_codec_context->extradata_size = input_codec_context->extradata_size;
- // Some codecs put the wrong ticks_per_frame in (in the thousands instead of tens)
- 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) {
- output_codec_context->time_base = input_codec_context->time_base;
- output_codec_context->time_base.num *= input_codec_context->ticks_per_frame;
- }
- else {
- output_codec_context->time_base = input_stream->time_base;
- }
- switch (input_codec_context->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- output_codec_context->channel_layout = input_codec_context->channel_layout;
- output_codec_context->sample_rate = input_codec_context->sample_rate;
- output_codec_context->channels = input_codec_context->channels;
- output_codec_context->frame_size = input_codec_context->frame_size;
- 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) {
- output_codec_context->block_align = 0;
- }
- else {
- output_codec_context->block_align = input_codec_context->block_align;
- }
- break;
- case AVMEDIA_TYPE_VIDEO:
- output_codec_context->pix_fmt = input_codec_context->pix_fmt;
- output_codec_context->width = input_codec_context->width;
- output_codec_context->height = input_codec_context->height;
- output_codec_context->has_b_frames = input_codec_context->has_b_frames;
- if (output_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
- output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
- }
- break;
- default:
- break;
- }
- return output_stream;
- }
- int main(int argc, char **argv)
- {
- if (argc != 5)
- {
- fprintf(stderr, "Usage: %s <input filename> <playlist filename> <output prefix> <segment length>\n", argv[0]);
- exit(1);
- }
- config_info config;
- memset(&config, 0, sizeof(config_info));
- config.input_filename = argv[1];
- config.output_playlist = argv[2];
- config.output_prefix = argv[3];
- config.segment_length = atoi(argv[4]);
- char *output_filename = (char*) malloc(sizeof(char) * (strlen(config.output_prefix) + 10));
- if (!output_filename)
- {
- fprintf(stderr, "Segmenter error: Could not allocate space for output filenames with prefix %s\n", config.output_prefix);
- exit(1);
- }
- av_register_all();
- AVInputFormat *input_format = av_find_input_format("mp4");
- if (!input_format)
- {
- fprintf(stderr, "Segmenter error: Could not find MP4 demuxer.\n");
- exit(1);
- }
- AVFormatContext *input_context = NULL;
- int ret = avformat_open_input(&input_context, config.input_filename, input_format, NULL);
- if (ret != 0)
- {
- fprintf(stderr, "Segmenter error: Could not open input file, make sure it is an MP4 file: %d\n", ret);
- exit(1);
- }
- if (avformat_find_stream_info(input_context, NULL) < 0)
- {
- fprintf(stderr, "Segmenter error Could not read stream information.\n");
- exit(1);
- }
- AVOutputFormat *output_format = av_guess_format("mpegts", NULL, NULL);
- if (!output_format)
- {
- fprintf(stderr, "Segmenter error: Could not find MPEG-TS muxer.\n");
- exit(1);
- }
- AVFormatContext *output_context = avformat_alloc_context();
- if (!output_context)
- {
- fprintf(stderr, "Segmenter error: Could not allocate output context.\n");
- exit(1);
- }
- output_context->oformat = output_format;
- int video_index = -1;
- int audio_index = -1;
- AVStream *video_stream;
- AVStream *audio_stream;
- int i;
- for (i = 0; i < input_context->nb_streams && (video_index < 0 || audio_index < 0); i++)
- {
- switch (input_context->streams[i]->codec->codec_type)
- {
- case AVMEDIA_TYPE_VIDEO:
- video_index = i;
- input_context->streams[i]->discard = AVDISCARD_NONE;
- video_stream = add_output_stream(output_context, input_context->streams[i]);
- break;
- case AVMEDIA_TYPE_AUDIO:
- audio_index = i;
- input_context->streams[i]->discard = AVDISCARD_NONE;
- audio_stream = add_output_stream(output_context, input_context->streams[i]);
- break;
- default:
- input_context->streams[i]->discard = AVDISCARD_ALL;
- break;
- }
- }
- if (video_index == -1 || audio_index == -1)
- {
- fprintf(stderr, "Segmenter error: Video or audio stream not found.\n");
- exit(1);
- }
- av_dump_format(output_context, 0, config.output_prefix, 1);
- AVCodec *codec = avcodec_find_decoder(video_stream->codec->codec_id);
- if (!codec)
- {
- fprintf(stderr, "Segmenter error: Could not find video decoder, key frames will not be honored.\n");
- }
- if (avcodec_open2(video_stream->codec, codec, NULL) < 0)
- {
- fprintf(stderr, "Segmenter error: Could not open video decoder, key frames will not be honored.\n");
- }
- // Generate output filename: <output_prefix>-<output_index>.ts
- unsigned int output_index = 1;
- snprintf(output_filename, strlen(config.output_prefix) + 10, "%s-%05u.ts", config.output_prefix, output_index++);
- fprintf(stdout, "First chunk: %s\n", output_filename);
- if (avio_open(&output_context->pb, output_filename, AVIO_FLAG_WRITE) < 0)
- {
- fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename);
- exit(1);
- }
- if (avformat_write_header(output_context, NULL))
- {
- fprintf(stderr, "Segmenter error: Could not write mpegts header to first output file.\n");
- exit(1);
- }
- // Required when muxing h264 into MPEG-TS
- AVBitStreamFilterContext *bsf = av_bitstream_filter_init("h264_mp4toannexb");
- if (!bsf)
- {
- fprintf(stderr, "Error initializing the h264_mp4toannexb filter!");
- exit(1);
- }
- double prev_segment_time = 0;
- int decode_done;
- do
- {
- double segment_time;
- AVPacket packet;
- decode_done = av_read_frame(input_context, &packet);
- if (decode_done < 0)
- {
- break;
- }
- if (av_dup_packet(&packet) < 0)
- {
- fprintf(stderr, "Segmenter error: Could not duplicate packet (av_dup_packet).\n");
- av_free_packet(&packet);
- break;
- }
- fprintf(stdout, "Read frame, keyframe: %u, index: %u\n", packet.flags & AV_PKT_FLAG_KEY, packet.stream_index);
- if (packet.stream_index == video_index)
- {
- AVPacket npacket = packet;
- int a = av_bitstream_filter_filter(bsf, video_stream->codec, NULL,
- &npacket.data, &npacket.size,
- packet.data, packet.size,
- packet.flags & AV_PKT_FLAG_KEY);
- if (a > 0)
- {
- av_free_packet(&packet);
- }
- else if (a == 0)
- {
- fprintf(stderr, "Eh?!\n");
- }
- else if (a < 0)
- {
- fprintf(stderr, "%s failed for stream %d, codec %s, error %d\n", bsf->filter->name, packet.stream_index, video_stream->codec->codec->name, a);
- exit(1);
- }
- packet = npacket;
- fprintf(stdout, "Did bitfilter fun!\n");
- }
- // Is this a key frame?
- if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY))
- {
- segment_time = (double)video_stream->pts.val * video_stream->time_base.num / video_stream->time_base.den;
- }
- else
- {
- segment_time = prev_segment_time;
- }
- if (segment_time - prev_segment_time >= config.segment_length)
- {
- fprintf(stdout, "Writing chunk with length %f and filename %s\n", segment_time - prev_segment_time, output_filename);
- fflush(stdout);
- avio_flush(output_context->pb);
- avio_close(output_context->pb);
- // Open next file
- snprintf(output_filename, strlen(config.output_prefix) + 10, "%s-%05u.ts", config.output_prefix, output_index++);
- if (avio_open(&output_context->pb, output_filename, AVIO_FLAG_WRITE) < 0)
- {
- fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename);
- exit(1);
- }
- prev_segment_time = segment_time;
- }
- ret = av_interleaved_write_frame(output_context, &packet);
- if (ret < 0)
- {
- fprintf(stderr, "Segmenter error: Could not write frame of stream: %d\n", ret);
- exit(1);
- }
- else if (ret > 0)
- {
- fprintf(stderr, "Segmenter info: End of stream requested.\n");
- av_free_packet(&packet);
- break;
- }
- //av_free_packet(&packet);
- } while (!decode_done);
- av_write_trailer(output_context);
- avcodec_close(video_stream->codec);
- for (i = 0; i < output_context->nb_streams; i++)
- {
- av_freep(&output_context->streams[i]->codec);
- av_freep(&output_context->streams[i]);
- }
- av_bitstream_filter_close(bsf);
- avio_close(output_context->pb);
- av_free(output_context);
- fprintf(stdout, "SUCCESS!!!\n");
- exit(0);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement