diff --git a/ffmpeg/ffmpeg.go b/ffmpeg/ffmpeg.go index 6ed3442dd9..b9d3aa9c3b 100755 --- a/ffmpeg/ffmpeg.go +++ b/ffmpeg/ffmpeg.go @@ -967,20 +967,8 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions) return nil, ErrorMap[ret] } } - // This version of the code has two internal transcoder implementations, original - // and a refactored version. By default, we want to run the former, to stay on the - // safe side, but then we want to progressively enable the latter, "risky". - // It will be done by means of environment variable LPMS_USE_NEW_TRANSCODE - _, ok := os.LookupEnv("LPMS_USE_NEW_TRANSCODE") - var use_new_transcode C.int - if ok { - glog.Info("LPMS new transcode enabled") - use_new_transcode = 1 - } else { - use_new_transcode = 0 - } - ret := int(C.lpms_transcode(inp, paramsPointer, resultsPointer, C.int(len(params)), decoded, use_new_transcode)) + ret := int(C.lpms_transcode(inp, paramsPointer, resultsPointer, C.int(len(params)), decoded)) if ret != 0 { if LogTranscodeErrors { glog.Error("Transcoder Return : ", ErrorMap[ret]) diff --git a/ffmpeg/transcoder.c b/ffmpeg/transcoder.c index 345fb4aebf..da7caf3492 100755 --- a/ffmpeg/transcoder.c +++ b/ffmpeg/transcoder.c @@ -280,282 +280,6 @@ void handle_discontinuity(struct input_ctx *ictx, AVPacket *pkt) } } -int handle_audio_frame(struct transcode_thread *h, AVStream *ist, output_results *decoded_results, AVFrame *dframe) -{ - struct input_ctx *ictx = &h->ictx; - - // frame duration update - int64_t dur = 0; - if (dframe->duration) { - dur = dframe->duration; - } else if (ist->r_frame_rate.den) { - dur = av_rescale_q(1, av_inv_q(ist->r_frame_rate), ist->time_base); - } else { - // TODO use better heuristics for this; look at how ffmpeg does it - LPMS_WARN("Could not determine next pts; filter might drop"); - } - dframe->duration = dur; - - // keep as last frame - av_frame_unref(ictx->last_frame_a); - av_frame_ref(ictx->last_frame_a, dframe); - - for (int i = 0; i < h->nb_outputs; i++) { - struct output_ctx *octx = h->outputs + i; - - if (octx->ac) { - int ret = process_out(ictx, octx, octx->ac, - octx->oc->streams[octx->dv ? 0 : 1], &octx->af, dframe); - if (AVERROR(EAGAIN) == ret || AVERROR_EOF == ret) continue; // this is ok - if (ret < 0) LPMS_ERR_RETURN("Error encoding audio"); - } - } - - return 0; -} - -int handle_video_frame(struct transcode_thread *h, AVStream *ist, output_results *decoded_results, AVFrame *dframe) -{ - struct input_ctx *ictx = &h->ictx; - - // TODO: this was removed, but need to investigate if safe - // if (is_flush_frame(dframe)) goto whileloop_end; - // if we are here, we know there is a frame - ++decoded_results->frames; - decoded_results->pixels += dframe->width * dframe->height; - - // frame duration update - int64_t dur = 0; - if (dframe->duration) { - dur = dframe->duration; - } else if (ist->r_frame_rate.den) { - dur = av_rescale_q(1, av_inv_q(ist->r_frame_rate), ist->time_base); - } else { - // TODO use better heuristics for this; look at how ffmpeg does it - LPMS_WARN("Could not determine next pts; filter might drop"); - } - dframe->duration = dur; - - // keep as last frame - av_frame_unref(ictx->last_frame_v); - av_frame_ref(ictx->last_frame_v, dframe); - - for (int i = 0; i < h->nb_outputs; i++) { - struct output_ctx *octx = h->outputs + i; - - if (octx->vc) { - int ret = process_out(ictx, octx, octx->vc, octx->oc->streams[0], &octx->vf, dframe); - if (AVERROR(EAGAIN) == ret || AVERROR_EOF == ret) continue; // this is ok - if (ret < 0) { - LPMS_ERR_RETURN("Error encoding video"); - } - } - } - - return 0; -} - -int handle_audio_packet(struct transcode_thread *h, output_results *decoded_results, - AVPacket *pkt, AVFrame *frame) -{ - // Packet processing part - struct input_ctx *ictx = &h->ictx; - AVStream *ist = ictx->ic->streams[pkt->stream_index]; - int ret = 0; - // TODO: separate counter for the audio packets. Old code had none - - // TODO: this could probably be done always, because it is a no-op if - // lpms_discontinuity() wasn't called - if (ictx->transmuxing) { - handle_discontinuity(ictx, pkt); - } - - // Check if there are outputs to which packet can be muxed "as is" - for (int i = 0; i < h->nb_outputs; i++) { - struct output_ctx *octx = h->outputs + i; - AVStream *ost = NULL; - // TODO: this is now global, but could easily be particular output option - // we could do for example one transmuxing output (more make no sense) - // and other could be transcoding ones - if (ictx->transmuxing) { - // When transmuxing every input stream has its direct counterpart - ost = octx->oc->streams[pkt->stream_index]; - } else if (pkt->stream_index == ictx->ai) { - // This is audio stream for this output, but do we need packet? - if (octx->da) continue; // drop audio - // If there is no encoder, then we are copying. Also the index of - // audio stream is 0 when we are dropping video and 1 otherwise - if (!octx->ac) ost = octx->oc->streams[octx->dv ? 0 : 1]; - } - - if (ost) { - if (pkt->stream_index == ictx->ai) { - // audio packet clipping - if (!octx->clip_audio_start_pts_found) { - octx->clip_audio_start_pts = pkt->pts; - octx->clip_audio_start_pts_found = 1; - } - if (octx->clip_to && octx->clip_audio_start_pts_found && pkt->pts > octx->clip_audio_to_pts + octx->clip_audio_start_pts) { - continue; - } - if (octx->clip_from && !octx->clip_started) { - // we want first frame to be video frame - continue; - } - if (octx->clip_from && pkt->pts < octx->clip_audio_from_pts + octx->clip_audio_start_pts) { - continue; - } - } - - AVPacket *opkt = av_packet_clone(pkt); - if (octx->clip_from && ist->index == ictx->ai) { - opkt->pts -= octx->clip_audio_from_pts + octx->clip_audio_start_pts; - } - ret = mux(opkt, ist->time_base, octx, ost); - av_packet_free(&opkt); - if (ret < 0) LPMS_ERR_RETURN("Audio packet muxing error"); - } - } - - // Packet processing finished, check if we should decode a frame - if (ictx->ai != pkt->stream_index) return 0; - if (!ictx->ac) return 0; - - // Try to decode - ret = avcodec_send_packet(ictx->ac, pkt); - if (ret < 0) { - LPMS_ERR_RETURN("Error sending audio packet to decoder"); - } - ret = avcodec_receive_frame(ictx->ac, frame); - if (ret == AVERROR(EAGAIN)) { - // This is not really an error. It may be that packet just fed into - // the decoder may be not enough to complete decoding. Upper level will - // get next packet and retry - return 0; - } else if (ret < 0) { - LPMS_ERR_RETURN("Error receiving audio frame from decoder"); - } else { - // Fine, we have frame, process it - return handle_audio_frame(h, ist, decoded_results, frame); - } -} - -int handle_video_packet(struct transcode_thread *h, output_results *decoded_results, - AVPacket *pkt, AVFrame *frame) -{ - // Packet processing part - struct input_ctx *ictx = &h->ictx; - AVStream *ist = ictx->ic->streams[pkt->stream_index]; - int ret = 0; - - // TODO: separate counter for the video packets. Old code was increasing - // video frames counter on video packets when transmuxing, which was - // misleading at best. Video packet counter can be updated on both - // transmuxing as well as normal packet processing - - if (!ictx->first_pkt && (pkt->flags & AV_PKT_FLAG_KEY)) { - // very first video packet, keep it - // TODO: this should be called first_video_pkt - ictx->first_pkt = av_packet_clone(pkt); - ictx->first_pkt->pts = -1; - } - - // TODO: this could probably be done always, because it is a no-op if - // lpms_discontinuity() wasn't called - if (ictx->transmuxing) { - handle_discontinuity(ictx, pkt); - } - - // Check if there are outputs to which packet can be muxed "as is" - for (int i = 0; i < h->nb_outputs; i++) { - struct output_ctx *octx = h->outputs + i; - AVStream *ost = NULL; - // TODO: this is now global, but could easily be particular output option - // we could do for example one transmuxing output (more make no sense) - // and other could be transcoding ones - if (ictx->transmuxing) { - // When transmuxing every input stream has its direct counterpart - ost = octx->oc->streams[pkt->stream_index]; - } else if (pkt->stream_index == ictx->vi) { - // This is video stream for this output, but do we need packet? - if (octx->dv) continue; // drop video - // If there is no encoder, then we are copying - if (!octx->vc) ost = octx->oc->streams[0]; - } - - if (ost) { - // need to mux in the packet - AVPacket *opkt = av_packet_clone(pkt); - ret = mux(opkt, ist->time_base, octx, ost); - av_packet_free(&opkt); - if (ret < 0) LPMS_ERR_RETURN("Video packet muxing error"); - } - } - - // Packet processing finished, check if we should decode a frame - if (ictx->vi != pkt->stream_index) return 0; - if (!ictx->vc) return 0; - - // Try to decode - ret = avcodec_send_packet(ictx->vc, pkt); - if (ret < 0) { - LPMS_ERR_RETURN("Error sending video packet to decoder"); - } - ictx->pkt_diff++; - ret = avcodec_receive_frame(ictx->vc, frame); - if (ret == AVERROR(EAGAIN)) { - // This is not really an error. It may be that packet just fed into - // the decoder may be not enough to complete decoding. Upper level will - // get next packet and retry - return 0; - } else if (ret < 0) { - LPMS_ERR_RETURN("Error receiving video frame from decoder"); - } else { - // TODO: this whole sentinel frame business and packet count is broken, - // because it assumes 1-to-1 relationship between packets and frames, and - // it won't be so in multislice streams. Also what if first packet is just - // parameter set and encoder doesn't have to decode when receiving one - if (!is_flush_frame(frame)) { - ictx->pkt_diff--; // decrease buffer count for non-sentinel video frames - if (ictx->flushing) ictx->sentinel_count = 0; - } - // Fine, we have frame, process it - return handle_video_frame(h, ist, decoded_results, frame); - } -} - -int handle_other_packet(struct transcode_thread *h, AVPacket *pkt) -{ - struct input_ctx *ictx = &h->ictx; - AVStream *ist = ictx->ic->streams[pkt->stream_index]; - int ret = 0; - - // TODO: this could probably be done always, because it is a no-op if - // lpms_discontinuity() wasn't called - if (ictx->transmuxing) { - handle_discontinuity(ictx, pkt); - } - - // Check if there are outputs to which packet can be muxed "as is" - for (int i = 0; i < h->nb_outputs; i++) { - struct output_ctx *octx = h->outputs + i; - AVStream *ost = NULL; - // TODO: this is now global, but could easily be particular output option - // we could do for example one transmuxing output (more make no sense) - // and other could be transcoding ones - if (ictx->transmuxing) { - // When transmuxing every input stream has its direct counterpart - ost = octx->oc->streams[pkt->stream_index]; - // need to mux in the packet - AVPacket *opkt = av_packet_clone(pkt); - ret = mux(opkt, ist->time_base, octx, ost); - av_packet_free(&opkt); - if (ret < 0) LPMS_ERR_RETURN("Other packet muxing error"); - } - } - - return 0; -} // TODO: right now this flushes filter and the encoders, this will be separated // in the future @@ -579,99 +303,6 @@ int flush_all_outputs(struct transcode_thread *h) return 0; } -int transcode2(struct transcode_thread *h, - input_params *inp, output_params *params, - output_results *decoded_results) -{ - struct input_ctx *ictx = &h->ictx; - AVStream *ist = NULL; - AVPacket *ipkt = NULL; - AVFrame *iframe = NULL; - int ret = 0; - - // TODO: allocation checks - ipkt = av_packet_alloc(); - iframe = av_frame_alloc(); - - // Main demuxing loop: process input packets till EOF in the input stream - while (1) { - ret = demux_in(ictx, ipkt); - // See what we got - if (ret == AVERROR_EOF) { - // no more input packets - break; - } else if (ret < 0) { - // demuxing error - LPMS_ERR_BREAK("Unable to read input"); - } - // all is fine, handle packet just received - ist = ictx->ic->streams[ipkt->stream_index]; - if (AVMEDIA_TYPE_VIDEO == ist->codecpar->codec_type) { - // video packet - ret = handle_video_packet(h, decoded_results, ipkt, iframe); - if (ret < 0) break; - } else if (AVMEDIA_TYPE_AUDIO == ist->codecpar->codec_type) { - // audio packet - ret = handle_audio_packet(h, decoded_results, ipkt, iframe); - if (ret < 0) break; - } else { - // other types of packets (used only for transmuxing) - handle_other_packet(h, ipkt); - if (ret < 0) break; - } - av_packet_unref(ipkt); - } - - // No more input packets. Demuxer finished work. But there may still - // be frames buffered in the decoder(s), and we need to drain/flush - - // TODO: this will also get splitted into video and audio flushing - // loops, but right now flush_in works for entire output, flushing - // both audio and video - while (1) { - int stream_index; - ret = flush_in(ictx, iframe, &stream_index); - if (AVERROR_EOF == ret) { - // No more frames, can break - break; - } - if (AVERROR(EAGAIN) == ret) { - // retry - continue; - } - if (ret < 0) LPMS_ERR_BREAK("Flushing failed"); - ist = ictx->ic->streams[stream_index]; - if (AVMEDIA_TYPE_VIDEO == ist->codecpar->codec_type) { - handle_video_frame(h, ist, decoded_results, iframe); - } else if (AVMEDIA_TYPE_AUDIO == ist->codecpar->codec_type) { - handle_audio_frame(h, ist, decoded_results, iframe); - } - } - - // No more input frames. Decoder(s) finished work. But there may still - // be frames buffered in the filters, and we need to flush them - // IMPORTANT: no handle_*_frame calls here because there is no more input - // frames. - // NOTE: this is "flush filters, flush decoders, flush muxers" all in one, - // it will get broken down in future - flush_all_outputs(h); - - // Processing finished - -transcode_cleanup: - if (ipkt) av_packet_free(&ipkt); - if (iframe) av_frame_free(&iframe); - - if (ictx->transmuxing) { - // transcode_shutdown() is not to be called when transmuxing - if (ictx->ic) { - avformat_close_input(&ictx->ic); - ictx->ic = NULL; - } - return 0; - } else return transcode_shutdown(h, ret); -} - int transcode(struct transcode_thread *h, input_params *inp, output_params *params, output_results *decoded_results) @@ -876,7 +507,7 @@ int transcode(struct transcode_thread *h, // MA: this should probably be merged with transcode_init, as it basically is a // part of initialization int lpms_transcode(input_params *inp, output_params *params, - output_results *results, int nb_outputs, output_results *decoded_results, int use_new) + output_results *results, int nb_outputs, output_results *decoded_results) { int ret = 0; struct transcode_thread *h = inp->handle; @@ -932,11 +563,7 @@ int lpms_transcode(input_params *inp, output_params *params, ret = transcode_init(h, inp, params, results); if (ret < 0) return ret; - if (use_new) { - ret = transcode2(h, inp, params, decoded_results); - } else { - ret = transcode(h, inp, params, decoded_results); - } + ret = transcode(h, inp, params, decoded_results); h->initialized = 1; return ret; } diff --git a/ffmpeg/transcoder.h b/ffmpeg/transcoder.h index 53ded33f35..89ac66c029 100755 --- a/ffmpeg/transcoder.h +++ b/ffmpeg/transcoder.h @@ -78,7 +78,7 @@ enum LPMSLogLevel { }; void lpms_init(enum LPMSLogLevel max_level); -int lpms_transcode(input_params *inp, output_params *params, output_results *results, int nb_outputs, output_results *decoded_results, int use_new); +int lpms_transcode(input_params *inp, output_params *params, output_results *results, int nb_outputs, output_results *decoded_results); int lpms_transcode_reopen_demux(input_params *inp); struct transcode_thread* lpms_transcode_new(); void lpms_transcode_stop(struct transcode_thread* handle);