int do_calculate_dr(const char *filename) { struct stream_context sc; struct dr_meter meter; int err; meter_init(&meter); err = sc_open(&sc, filename); if (err < 0) { return print_av_error("sc_open", err); } int stream_index = err = av_find_best_stream( sc.format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); if (err < 0) { print_av_error("av_find_best_stream", err); goto cleanup; } err = sc_start_stream(&sc, stream_index); if (err < 0) { print_av_error("sc_start_stream", err); goto cleanup; } // Print out the stream info AVCodecContext *codec_ctx = sc_get_codec(&sc); char codecinfobuf[256]; avcodec_string(codecinfobuf, sizeof(codecinfobuf), codec_ctx, 0); fprintf(stderr, "%.256s\n", codecinfobuf); err = meter_start(&meter, codec_ctx->channels, codec_ctx->sample_rate, codec_ctx->sample_fmt); if (err) { goto cleanup; } fprintf(stderr, "Collecting fragments information...\n"); size_t fragment = 0; int throbbler_stage = 0; while (!sc_eof(&sc)) { err = sc_get_next_frame(&sc); if (err < 0) { print_av_error("sc_get_next_frame", err); goto cleanup; } err = meter_feed(&meter, sc.buf, sc.buf_size); if (err) { goto cleanup; } if (fragment < meter.fragment) { fragment = meter.fragment; if ((throbbler_stage % 4) == 0) { fprintf(stderr, "\033[1K\033[1G %c %2i:%02i ", throbbler[throbbler_stage / 4], (fragment * 3) / 60, (fragment * 3) % 60); } throbbler_stage += 1; throbbler_stage %= 16; } } meter_finish(&meter); cleanup: meter_free(&meter); sc_close(&sc); if (err < 0) { return err; } return 0; }
int calculate_track_dr(const char *filename, struct track_info *t, int number) { struct stream_context sc; struct dr_meter meter; int err; meter_init(&meter); err = sc_open(&sc, filename); if (err < 0) { return print_av_error("sc_open", err); } if (debug) { printf("DEBUG: Codec: %s\n", avcodec_get_name(sc_get_codec_id(&sc))); } int stream_index = err = av_find_best_stream( sc.format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); if (err < 0) { print_av_error("av_find_best_stream", err); goto cleanup; } err = sc_start_stream(&sc, stream_index); if (err < 0) { print_av_error("sc_start_stream", err); goto cleanup; } t->artist = strdup(sc_get_metadata(&sc, "artist")); t->album = strdup(sc_get_metadata(&sc, "album")); t->tracknumber = strdup(sc_get_metadata(&sc, "track")); t->title = strdup(sc_get_metadata(&sc, "title")); AVCodecParameters *codecpar = sc_get_codec_parameters(&sc); err = meter_start(&meter, codecpar->channels, codecpar->sample_rate, codecpar->format); if (err) { goto cleanup; } size_t fragment = 0; int throbbler_stage = 0; while (!sc_eof(&sc)) { err = sc_get_next_frame(&sc); if (err < 0) { print_av_error("sc_get_next_frame", err); goto cleanup; } err = meter_feed(&meter, sc_get_buf(&sc), sc_get_samples(&sc)); if (err) { goto cleanup; } if (fragment < meter.fragment) { fragment = meter.fragment; if ((throbbler_stage % 4) == 0) { fprintf(stderr, "\033[1K\033[1G" "Analyzing track %i... " "%c %2zu:%02zu ", number, throbbler[throbbler_stage / 4], (fragment * 3) / 60, (fragment * 3) % 60); } throbbler_stage += 1; throbbler_stage %= 16; } } fprintf(stderr, "\033[1K\033[1G"); meter_finish(&meter, t); cleanup: meter_free(&meter); sc_close(&sc); if (err < 0) { return err; } return 0; }
int segment_process(struct config_info config) { unsigned int output_filename_size = sizeof(char) * (strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 100); char *output_filename = malloc(output_filename_size); if (!output_filename) { fprintf(stderr, "Segmenter error: Could not allocate space for output filenames\n"); exit(1); } // we try to approximate the time of first received frame // by taking system timestamp and storing first frame timestamp time_t sys_time; time(&sys_time); double on_start_timestamp = (double)sys_time; av_register_all(); AVInputFormat *input_format = av_find_input_format("mpegts"); if (!input_format) { fprintf(stderr, "Segmenter error: Could not find MPEG-TS demuxer\n"); exit(1); } AVFormatContext *input_context = NULL; int ret; ret = avformat_open_input(&input_context, config.input_filename, input_format, NULL); if (ret != 0) { print_av_error("Could not open input file, make sure it is an mpegts", ret); exit(1); } ret = avformat_find_stream_info(input_context, NULL); if (ret < 0) { print_av_error("Could not read stream information", ret); exit(1); } fprintf(stderr, "segmenter-debug: start time %lld %lld \n", input_context->start_time, input_context->timestamp); 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 allocated output context"); exit(1); } output_context->oformat = output_format; int video_index = -1; int audio_index = -1; AVStream *video_stream; AVStream *audio_stream; int i; int index_map[20]; memset (index_map, -1, sizeof(int)*20); 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]); index_map[i] = video_stream->index; 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]); index_map[i] = audio_stream->index; break; default: input_context->streams[i]->discard = AVDISCARD_ALL; fprintf(stderr, "segmenter-warning: stream index %d from source woudl be skipped \n", i); break; } } #if LIBAVFORMAT_VERSION_MAJOR < 54 if (av_set_parameters(output_context, NULL) < 0) { fprintf(stderr, "Segmenter error: Invalid output format parameters\n"); exit(1); } #endif av_dump_format(output_context, 0, config.filename_prefix, 1); if(video_index >= 0) { 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"); } } unsigned int output_index = 1; snprintf(output_filename, output_filename_size, "%s/%s-%u-%010u.ts", config.temp_directory, config.filename_prefix, config.run_cycle, 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); } if (avformat_write_header(output_context, NULL)) { fprintf(stderr, "Segmenter error: Could not write mpegts header to first output file\n"); exit(1); } unsigned int first_segment = 1; unsigned int last_segment = 0; double prev_segment_time = 0; double first_segment_time = -1.0; int decode_done; double segment_time = 0; unsigned int pktWriteFrameErrorCount = 0; do { AVPacket packet; decode_done = av_read_frame(input_context, &packet); if (decode_done < 0) { break; } if ((ret = av_dup_packet(&packet)) < 0) { print_av_error("Could not duplicate packet", ret); av_free_packet(&packet); break; } 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; if (first_segment_time <= 0) fprintf(stderr, "segmenter-debug: received new time from video I frame : %lf\n", segment_time); } else if (video_index < 0) { segment_time = (double)audio_stream->pts.val * audio_stream->time_base.num / audio_stream->time_base.den; if (first_segment_time <= 0) fprintf(stderr, "segmenter-debug: received new time from audio PTS : %lf\n", segment_time); } else { segment_time = prev_segment_time; } // initialy previous segment time would be zero, avoid receiving huge difference if (prev_segment_time == 0 && segment_time > 0) { prev_segment_time = segment_time; } if (first_segment_time < 0 && segment_time > 0) { first_segment_time = segment_time; // this is relative time in MS } //fprintf(stderr, "segmenter-debug: videoPTS=%lf audioPTS=%lf\n", (double)video_stream->pts.val * video_stream->time_base.num / video_stream->time_base.den, (double)audio_stream->pts.val * audio_stream->time_base.num / audio_stream->time_base.den); //fprintf(stderr, "segmenter-debug: cur=%.02lf prev=%.02lf onstartTS=%.02lf first=%.02lf\n", segment_time, prev_segment_time, on_start_timestamp, first_segment_time); // timestamps in the streams received from IRDs are relative, // if there's a mismatch - time to restart segmentation process, as entire TS may change // done writing the current file? if (segment_time - prev_segment_time >= config.segment_length) { avio_flush(output_context->pb); avio_close(output_context->pb); output_transfer_command(++last_segment, (segment_time-first_segment_time+on_start_timestamp), (segment_time-prev_segment_time), 0, output_filename); snprintf(output_filename, output_filename_size, "%s/%s-%u-%010u.ts", config.temp_directory, config.filename_prefix, config.run_cycle,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); break; } prev_segment_time = segment_time; } // because indicies from original and destination packets differ, perform correction if (index_map[packet.stream_index] < 0) { fprintf(stderr, "segmenter-debug: skipping packet pos=%lld size=%d stream=%d flags=%d pts=%lld\n", packet.pos, packet.size, packet.stream_index, packet.flags, packet.pts); ret = -1000; }else if (packet.size > 0) { packet.stream_index = index_map[packet.stream_index]; ret = av_interleaved_write_frame(output_context, &packet); // fprintf(stderr, "segmenter-error: [%d] handling packet pos=%lld size=%d stream=%d flags=%d pts=%lld\n", ret, packet.pos, packet.size, packet.stream_index, packet.flags, packet.pts); }else{ fprintf(stderr, "segmenter-debug: empty packet\n"); ret = -1001; } av_free_packet(&packet); if (ret < 0) { // fprintf(stderr, "segmenter-error: handling packet pos=%lld size=%d stream=%d flags=%d pts=%lld\n", packet.pos, packet.size, packet.stream_index, packet.flags, packet.pts); // print_av_error("av_interleaved_write_frame ",ret); pktWriteFrameErrorCount ++; if (first_segment_time > 0 && pktWriteFrameErrorCount > PKT_WRITE_FRAME_ERROR_LIMIT) { fprintf(stderr, "segmenter-error: can't handle last %u packets. requesting process restart.\n", pktWriteFrameErrorCount); break; } } else if (ret > 0) { fprintf(stderr, "Segmenter info: End of stream requested\n"); av_free_packet(&packet); break; }else{ pktWriteFrameErrorCount = 0; // clear av_interleaved_write_frame() error count } } while (!decode_done); av_write_trailer(output_context); if (video_index >= 0) { 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]); } avio_close(output_context->pb); av_free(output_context); av_close_input_file(input_context); output_transfer_command(++last_segment, (segment_time-first_segment_time+on_start_timestamp), (segment_time-prev_segment_time), 1, output_filename); return 0; }