/// /// @file codec.c @brief Codec functions /// /// Copyright (c) 2009 - 2015 by Johns. All Rights Reserved. /// /// Contributor(s): /// /// License: AGPLv3 /// /// This program is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as /// published by the Free Software Foundation, either version 3 of the /// License. /// /// This program is distributed in the hope that it will be useful, /// but WITHOUT ANY WARRANTY; without even the implied warranty of /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /// GNU Affero General Public License for more details. /// /// $Id: d285eb28485bea02cd205fc8be47320dfe0376cf $ ////////////////////////////////////////////////////////////////////////////// /// /// @defgroup Codec The codec module. /// /// This module contains all decoder and codec functions. /// It is uses ffmpeg (http://ffmpeg.org) as backend. /// /// It may work with libav (http://libav.org), but the tests show /// many bugs and incompatiblity in it. Don't use this shit. /// /// compile with pass-through support (stable, AC-3, E-AC-3 only) #define USE_PASSTHROUGH /// compile audio drift correction support (very experimental) #define USE_AUDIO_DRIFT_CORRECTION /// compile AC-3 audio drift correction support (very experimental) #define USE_AC3_DRIFT_CORRECTION /// use ffmpeg libswresample API (autodected, Makefile) #define noUSE_SWRESAMPLE /// use libav libavresample API (autodected, Makefile) #define noUSE_AVRESAMPLE #include #include #include #include #ifdef __FreeBSD__ #include #else #include #endif #include #include #include #include #define _(str) gettext(str) ///< gettext shortcut #define _N(str) str ///< gettext_noop shortcut #include #include #include #ifdef USE_SWRESAMPLE #include #endif #ifdef USE_AVRESAMPLE #include #include #endif #ifndef __USE_GNU #define __USE_GNU #endif #include // clang-format off #include "iatomic.h" #include "misc.h" #include "video.h" #include "audio.h" #include "codec.h" // clang-format on //---------------------------------------------------------------------------- // Global //---------------------------------------------------------------------------- /// /// ffmpeg lock mutex /// /// new ffmpeg dislikes simultanous open/close /// this breaks our code, until this is fixed use lock. /// static pthread_mutex_t CodecLockMutex; /// Flag prefer fast channel switch char CodecUsePossibleDefectFrames; AVBufferRef *hw_device_ctx; //---------------------------------------------------------------------------- // Video //---------------------------------------------------------------------------- #if 0 /// /// Video decoder typedef. /// //typedef struct _video_decoder_ Decoder; #endif #if 0 /// /// Video decoder structure. /// struct _video_decoder_ { VideoHwDecoder *HwDecoder; ///< video hardware decoder int GetFormatDone; ///< flag get format called! AVCodec *VideoCodec; ///< video codec AVCodecContext *VideoCtx; ///< video codec context AVFrame *Frame; ///< decoded video frame }; #endif //---------------------------------------------------------------------------- // Call-backs //---------------------------------------------------------------------------- /** ** Callback to negotiate the PixelFormat. ** ** @param video_ctx codec context ** @param fmt is the list of formats which are supported by ** the codec, it is terminated by -1 as 0 is a ** valid format, the formats are ordered by ** quality. */ static enum AVPixelFormat Codec_get_format(AVCodecContext *video_ctx, const enum AVPixelFormat *fmt) { VideoDecoder *decoder; enum AVPixelFormat fmt1; decoder = video_ctx->opaque; // bug in ffmpeg 1.1.1, called with zero width or height if (!video_ctx->width || !video_ctx->height) { Error("codec/video: ffmpeg/libav buggy: width or height zero\n"); } // decoder->GetFormatDone = 1; return Video_get_format(decoder->HwDecoder, video_ctx, fmt); } // static void Codec_free_buffer(void *opaque, uint8_t *data); /** ** Video buffer management, get buffer for frame. ** ** Called at the beginning of each frame to get a buffer for it. ** ** @param video_ctx Codec context ** @param frame Get buffer for this frame */ static int Codec_get_buffer2(AVCodecContext *video_ctx, AVFrame *frame, int flags) { VideoDecoder *decoder; decoder = video_ctx->opaque; if (!decoder->GetFormatDone) { // get_format missing enum AVPixelFormat fmts[2]; // fprintf(stderr, "codec: buggy libav, use ffmpeg\n"); // Warning(_("codec: buggy libav, use ffmpeg\n")); fmts[0] = video_ctx->pix_fmt; fmts[1] = AV_PIX_FMT_NONE; Codec_get_format(video_ctx, fmts); } #if 0 if (decoder->hwaccel_get_buffer && (AV_PIX_FMT_VDPAU == decoder->hwaccel_pix_fmt || AV_PIX_FMT_CUDA == decoder->hwaccel_pix_fmt || AV_PIX_FMT_VAAPI == decoder->hwaccel_pix_fmt)) { // Debug(3,"hwaccel get_buffer\n"); return decoder->hwaccel_get_buffer(video_ctx, frame, flags); } #endif // Debug(3, "codec: fallback to default get_buffer\n"); return avcodec_default_get_buffer2(video_ctx, frame, flags); } //---------------------------------------------------------------------------- // Test //---------------------------------------------------------------------------- /** ** Allocate a new video decoder context. ** ** @param hw_decoder video hardware decoder ** ** @returns private decoder pointer for video decoder. */ VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder *hw_decoder) { VideoDecoder *decoder; if (!(decoder = calloc(1, sizeof(*decoder)))) { Fatal(_("codec: can't allocate vodeo decoder\n")); } decoder->HwDecoder = hw_decoder; return decoder; } /** ** Deallocate a video decoder context. ** ** @param decoder private video decoder */ void CodecVideoDelDecoder(VideoDecoder *decoder) { free(decoder); } /** ** Open video decoder. ** ** @param decoder private video decoder ** @param codec_id video codec id */ void CodecVideoOpen(VideoDecoder *decoder, int codec_id) { AVCodec *video_codec; const char *name; int ret, deint = 2; Debug(3, "***************codec: Video Open using video codec ID %#06x (%s)\n", codec_id, avcodec_get_name(codec_id)); if (decoder->VideoCtx) { Error(_("codec: missing close\n")); } name = "NULL"; #ifdef CUVID if (!strcasecmp(VideoGetDriverName(), "cuvid")) { switch (codec_id) { case AV_CODEC_ID_MPEG2VIDEO: name = "mpeg2_cuvid"; break; case AV_CODEC_ID_H264: name = "h264_cuvid"; break; case AV_CODEC_ID_HEVC: name = "hevc_cuvid"; break; } } #endif #ifdef RASPI switch (codec_id) { case AV_CODEC_ID_MPEG2VIDEO: name = "mpeg2_v4l2m2m"; break; case AV_CODEC_ID_H264: name = "h264_v4l2m2m"; // name = "h264_mmal"; break; case AV_CODEC_ID_HEVC: name = "hevc_v4l2m2m"; break; } #endif if (name && (video_codec = avcodec_find_decoder_by_name(name))) { Debug(3, "codec: decoder found\n"); } else if ((video_codec = avcodec_find_decoder(codec_id)) == NULL) { Debug(3, "Decoder %s not supported %p\n", name, video_codec); Fatal(_(" No decoder found")); } decoder->VideoCodec = video_codec; Debug(3, "codec: video '%s'\n", decoder->VideoCodec->long_name); if (!(decoder->VideoCtx = avcodec_alloc_context3(video_codec))) { Fatal(_("codec: can't allocate video codec context\n")); } #ifndef RASPI if (!HwDeviceContext) { Fatal("codec: no hw device context to be used"); } decoder->VideoCtx->hw_device_ctx = av_buffer_ref(HwDeviceContext); #else decoder->VideoCtx->pix_fmt = AV_PIX_FMT_DRM_PRIME; /* request a DRM frame */ // decoder->VideoCtx->pix_fmt = AV_PIX_FMT_MMAL; /* request a DRM frame //*/ #endif // FIXME: for software decoder use all cpus, otherwise 1 decoder->VideoCtx->thread_count = 1; decoder->VideoCtx->pkt_timebase.num = 1; decoder->VideoCtx->pkt_timebase.den = 90000; decoder->VideoCtx->framerate.num = 50; decoder->VideoCtx->framerate.den = 1; pthread_mutex_lock(&CodecLockMutex); // open codec #ifdef YADIF deint = 2; #endif #if defined VAAPI && !defined RASPI // decoder->VideoCtx->extra_hw_frames = 8; // VIDEO_SURFACES_MAX +1 if (video_codec->capabilities & (AV_CODEC_CAP_AUTO_THREADS)) { Debug(3, "codec: auto threads enabled"); // decoder->VideoCtx->thread_count = 0; } if (video_codec->capabilities & AV_CODEC_CAP_TRUNCATED) { Debug(3, "codec: supports truncated packets"); // decoder->VideoCtx->flags |= CODEC_FLAG_TRUNCATED; } // FIXME: own memory management for video frames. if (video_codec->capabilities & AV_CODEC_CAP_DR1) { Debug(3, "codec: can use own buffer management"); } if (video_codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) { Debug(3, "codec: supports frame threads"); // decoder->VideoCtx->thread_count = 0; // decoder->VideoCtx->thread_type |= FF_THREAD_FRAME; } if (video_codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) { Debug(3, "codec: supports slice threads"); // decoder->VideoCtx->thread_count = 0; // decoder->VideoCtx->thread_type |= FF_THREAD_SLICE; } // if (av_opt_set_int(decoder->VideoCtx, "refcounted_frames", 1, 0) < 0) // Fatal(_("VAAPI Refcounts invalid\n")); decoder->VideoCtx->thread_safe_callbacks = 0; #endif #ifdef RASPI decoder->VideoCtx->codec_id = codec_id; decoder->VideoCtx->flags |= AV_CODEC_FLAG_BITEXACT; if (video_codec->capabilities & AV_CODEC_CAP_FRAME_THREADS || AV_CODEC_CAP_SLICE_THREADS) { Debug(3, "codec: supports frame threads"); decoder->VideoCtx->thread_count = 4; // decoder->VideoCtx->thread_type |= FF_THREAD_FRAME; } if (video_codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) { Debug(3, "codec: supports slice threads"); decoder->VideoCtx->thread_type |= FF_THREAD_SLICE; } #endif #ifdef CUVID if (strcmp(decoder->VideoCodec->long_name, "Nvidia CUVID MPEG2VIDEO decoder") == 0) { // deinterlace for mpeg2 is somehow broken if (av_opt_set_int(decoder->VideoCtx->priv_data, "deint", deint, 0) < 0) { // adaptive pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't set option deint to video codec!\n")); } #if 1 if (av_opt_set_int(decoder->VideoCtx->priv_data, "surfaces", 9, 0) < 0) { pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't set option surfces to video codec!\n")); } #endif if (av_opt_set(decoder->VideoCtx->priv_data, "drop_second_field", "false", 0) < 0) { pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't set option drop 2.field to video codec!\n")); } } else if (strstr(decoder->VideoCodec->long_name, "Nvidia CUVID") != NULL) { if (av_opt_set_int(decoder->VideoCtx->priv_data, "deint", deint, 0) < 0) { // adaptive pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't set option deint to video codec!\n")); } #if 1 if (av_opt_set_int(decoder->VideoCtx->priv_data, "surfaces", 13, 0) < 0) { pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't set option surfces to video codec!\n")); } #endif if (av_opt_set(decoder->VideoCtx->priv_data, "drop_second_field", "false", 0) < 0) { pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't set option drop 2.field to video codec!\n")); } } #endif if ((ret = avcodec_open2(decoder->VideoCtx, video_codec, NULL)) < 0) { pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't open video codec!\n")); } Debug(3, " Codec open %d\n", ret); pthread_mutex_unlock(&CodecLockMutex); decoder->VideoCtx->opaque = decoder; // our structure // decoder->VideoCtx->debug = FF_DEBUG_STARTCODE; // decoder->VideoCtx->err_recognition |= AV_EF_EXPLODE; // av_log_set_level(AV_LOG_DEBUG); av_log_set_level(0); decoder->VideoCtx->get_format = Codec_get_format; decoder->VideoCtx->get_buffer2 = Codec_get_buffer2; // decoder->VideoCtx->active_thread_type = 0; decoder->VideoCtx->draw_horiz_band = NULL; decoder->VideoCtx->hwaccel_context = VideoGetHwAccelContext(decoder->HwDecoder); // // Prepare frame buffer for decoder // #if 0 if (!(decoder->Frame = av_frame_alloc())) { Fatal(_("codec: can't allocate video decoder frame buffer\n")); } #endif // reset buggy ffmpeg/libav flag decoder->GetFormatDone = 0; #if defined(YADIF) || defined(RASPI) decoder->filter = 0; #endif } /** ** Close video decoder. ** ** @param video_decoder private video decoder */ void CodecVideoClose(VideoDecoder *video_decoder) { AVFrame *frame; // FIXME: play buffered data // av_frame_free(&video_decoder->Frame); // callee does checks Debug(3, "CodecVideoClose\n"); if (video_decoder->VideoCtx) { pthread_mutex_lock(&CodecLockMutex); #if 1 frame = av_frame_alloc(); avcodec_send_packet(video_decoder->VideoCtx, NULL); while (avcodec_receive_frame(video_decoder->VideoCtx, frame) >= 0) ; av_frame_free(&frame); #endif avcodec_close(video_decoder->VideoCtx); av_freep(&video_decoder->VideoCtx); pthread_mutex_unlock(&CodecLockMutex); } } #if 0 /** ** Display pts... ** ** ffmpeg-0.9 pts always AV_NOPTS_VALUE ** ffmpeg-0.9 pkt_pts nice monotonic (only with HD) ** ffmpeg-0.9 pkt_dts wild jumping -160 - 340 ms ** ** libav 0.8_pre20111116 pts always AV_NOPTS_VALUE ** libav 0.8_pre20111116 pkt_pts always 0 (could be fixed?) ** libav 0.8_pre20111116 pkt_dts wild jumping -160 - 340 ms */ void DisplayPts(AVCodecContext * video_ctx, AVFrame * frame) { int ms_delay; int64_t pts; static int64_t last_pts; pts = frame->pkt_pts; if (pts == (int64_t) AV_NOPTS_VALUE) { printf("*"); } ms_delay = (1000 * video_ctx->time_base.num) / video_ctx->time_base.den; ms_delay += frame->repeat_pict * ms_delay / 2; printf("codec: PTS %s%s %" PRId64 " %d %d/%d %d/%d %dms\n", frame->repeat_pict ? "r" : " ", frame->interlaced_frame ? "I" : " ", pts, (int)(pts - last_pts) / 90, video_ctx->time_base.num, video_ctx->time_base.den, video_ctx->framerate.num, video_ctx->framerate.den, ms_delay); if (pts != (int64_t) AV_NOPTS_VALUE) { last_pts = pts; } } #endif /** ** Decode a video packet. ** ** @param decoder video decoder data ** @param avpkt video packet */ extern int CuvidTestSurfaces(); #if defined YADIF || defined(VAAPI) extern int init_filters(AVCodecContext *dec_ctx, void *decoder, AVFrame *frame); extern int push_filters(AVCodecContext *dec_ctx, void *decoder, AVFrame *frame); #endif #ifdef VAAPI void CodecVideoDecode(VideoDecoder *decoder, const AVPacket *avpkt) { AVCodecContext *video_ctx = decoder->VideoCtx; if (video_ctx->codec_type == AVMEDIA_TYPE_VIDEO && CuvidTestSurfaces()) { int ret; AVPacket pkt[1]; AVFrame *frame; *pkt = *avpkt; // use copy ret = avcodec_send_packet(video_ctx, pkt); if (ret < 0) { return; } if (!CuvidTestSurfaces()) usleep(1000); ret = 0; while (ret >= 0 && CuvidTestSurfaces()) { frame = av_frame_alloc(); ret = avcodec_receive_frame(video_ctx, frame); if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { Debug(4, "codec: receiving video frame failed"); av_frame_free(&frame); return; } if (ret >= 0) { if (decoder->filter) { if (decoder->filter == 1) { if (init_filters(video_ctx, decoder->HwDecoder, frame) < 0) { Debug(3, "video: Init of VAAPI deint Filter failed\n"); decoder->filter = 0; } else { Debug(3, "Init VAAPI deint ok\n"); decoder->filter = 2; } } if (frame->interlaced_frame && decoder->filter == 2 && (frame->height != 720)) { // broken ZDF sends Interlaced flag push_filters(video_ctx, decoder->HwDecoder, frame); continue; } } VideoRenderFrame(decoder->HwDecoder, video_ctx, frame); } else { av_frame_free(&frame); return; } } } } #endif #ifdef CUVID void CodecVideoDecode(VideoDecoder *decoder, const AVPacket *avpkt) { AVCodecContext *video_ctx; AVFrame *frame; int ret, ret1; int got_frame; int consumed = 0; static uint64_t first_time = 0; const AVPacket *pkt; next_part: video_ctx = decoder->VideoCtx; pkt = avpkt; // use copy got_frame = 0; // printf("decode packet %d\n",(GetusTicks()-first_time)/1000000); ret1 = avcodec_send_packet(video_ctx, pkt); // first_time = GetusTicks(); if (ret1 >= 0) { consumed = 1; } if (!CuvidTestSurfaces()) usleep(1000); // printf("send packet to decode %s %04x\n",consumed?"ok":"Full",ret1); if ((ret1 == AVERROR(EAGAIN) || ret1 == AVERROR_EOF || ret1 >= 0) && CuvidTestSurfaces()) { ret = 0; while ((ret >= 0) && CuvidTestSurfaces()) { // get frames until empty snd Surfaces avail. frame = av_frame_alloc(); ret = avcodec_receive_frame(video_ctx, frame); // get new frame if (ret >= 0) { // one is avail. got_frame = 1; } else { got_frame = 0; } // printf("got %s packet from // decoder\n",got_frame?"1":"no"); if (got_frame) { // frame completed // printf("video frame pts %#012" PRIx64 " //%dms\n",frame->pts,(int)(apts - frame->pts) / 90); #ifdef YADIF if (decoder->filter) { if (decoder->filter == 1) { if (init_filters(video_ctx, decoder->HwDecoder, frame) < 0) { Fatal(_("video: Init of YADIF Filter failed\n")); decoder->filter = 0; } else { Debug(3, "Init YADIF ok\n"); decoder->filter = 2; } } if (frame->interlaced_frame && decoder->filter == 2 && (frame->height != 720)) { // broken ZDF sends Interlaced flag ret = push_filters(video_ctx, decoder->HwDecoder, frame); // av_frame_unref(frame); continue; } } #endif // DisplayPts(video_ctx, frame); VideoRenderFrame(decoder->HwDecoder, video_ctx, frame); // av_frame_unref(frame); } else { av_frame_free(&frame); // printf("codec: got no frame %d send %d\n",ret,ret1); } } if (!CuvidTestSurfaces()) { usleep(1000); } } else { // consumed = 1; } if (!consumed) { goto next_part; // try again to stuff decoder } } #endif /** ** Flush the video decoder. ** ** @param decoder video decoder data */ void CodecVideoFlushBuffers(VideoDecoder *decoder) { if (decoder->VideoCtx) { avcodec_flush_buffers(decoder->VideoCtx); } } //---------------------------------------------------------------------------- // Audio //---------------------------------------------------------------------------- #if 0 /// /// Audio decoder typedef. /// typedef struct _audio_decoder_ AudioDecoder; #endif /// /// Audio decoder structure. /// struct _audio_decoder_ { AVCodec *AudioCodec; ///< audio codec AVCodecContext *AudioCtx; ///< audio codec context char Passthrough; ///< current pass-through flags int SampleRate; ///< current stream sample rate int Channels; ///< current stream channels int HwSampleRate; ///< hw sample rate int HwChannels; ///< hw channels AVFrame *Frame; ///< decoded audio frame buffer #ifdef USE_SWRESAMPLE #if LIBSWRESAMPLE_VERSION_INT < AV_VERSION_INT(0, 15, 100) struct SwrContext *Resample; ///< ffmpeg software resample context #else SwrContext *Resample; ///< ffmpeg software resample context #endif #endif #ifdef USE_AVRESAMPLE AVAudioResampleContext *Resample; ///< libav software resample context #endif uint16_t Spdif[24576 / 2]; ///< SPDIF output buffer int SpdifIndex; ///< index into SPDIF output buffer int SpdifCount; ///< SPDIF repeat counter int64_t LastDelay; ///< last delay struct timespec LastTime; ///< last time int64_t LastPTS; ///< last PTS int Drift; ///< accumulated audio drift int DriftCorr; ///< audio drift correction value int DriftFrac; ///< audio drift fraction for ac3 }; /// /// IEC Data type enumeration. /// enum IEC61937 { IEC61937_AC3 = 0x01, ///< AC-3 data // FIXME: more data types IEC61937_EAC3 = 0x15, ///< E-AC-3 data }; #ifdef USE_AUDIO_DRIFT_CORRECTION #define CORRECT_PCM 1 ///< do PCM audio-drift correction #define CORRECT_AC3 2 ///< do AC-3 audio-drift correction static char CodecAudioDrift; ///< flag: enable audio-drift correction #else static const int CodecAudioDrift = 0; #endif #ifdef USE_PASSTHROUGH /// /// Pass-through flags: CodecPCM, CodecAC3, CodecEAC3, ... /// static char CodecPassthrough; #else static const int CodecPassthrough = 0; #endif static char CodecDownmix; ///< enable AC-3 decoder downmix /** ** Allocate a new audio decoder context. ** ** @returns private decoder pointer for audio decoder. */ AudioDecoder *CodecAudioNewDecoder(void) { AudioDecoder *audio_decoder; if (!(audio_decoder = calloc(1, sizeof(*audio_decoder)))) { Fatal(_("codec: can't allocate audio decoder\n")); } if (!(audio_decoder->Frame = av_frame_alloc())) { Fatal(_("codec: can't allocate audio decoder frame buffer\n")); } return audio_decoder; } /** ** Deallocate an audio decoder context. ** ** @param decoder private audio decoder */ void CodecAudioDelDecoder(AudioDecoder *decoder) { av_frame_free(&decoder->Frame); // callee does checks free(decoder); } /** ** Open audio decoder. ** ** @param audio_decoder private audio decoder ** @param codec_id audio codec id */ void CodecAudioOpen(AudioDecoder *audio_decoder, int codec_id) { AVCodec *audio_codec; Debug(3, "codec: using audio codec ID %#06x (%s)\n", codec_id, avcodec_get_name(codec_id)); if (!(audio_codec = avcodec_find_decoder(codec_id))) { // if (!(audio_codec = avcodec_find_decoder(codec_id))) { Fatal(_("codec: codec ID %#06x not found\n"), codec_id); // FIXME: errors aren't fatal } audio_decoder->AudioCodec = audio_codec; if (!(audio_decoder->AudioCtx = avcodec_alloc_context3(audio_codec))) { Fatal(_("codec: can't allocate audio codec context\n")); } if (CodecDownmix) { audio_decoder->AudioCtx->request_channel_layout = AV_CH_LAYOUT_STEREO; } pthread_mutex_lock(&CodecLockMutex); // open codec if (1) { AVDictionary *av_dict; av_dict = NULL; // FIXME: import settings // av_dict_set(&av_dict, "dmix_mode", "0", 0); // av_dict_set(&av_dict, "ltrt_cmixlev", "1.414", 0); // av_dict_set(&av_dict, "loro_cmixlev", "1.414", 0); if (avcodec_open2(audio_decoder->AudioCtx, audio_codec, &av_dict) < 0) { pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't open audio codec\n")); } av_dict_free(&av_dict); } pthread_mutex_unlock(&CodecLockMutex); Debug(3, "codec: audio '%s'\n", audio_decoder->AudioCodec->long_name); audio_decoder->SampleRate = 0; audio_decoder->Channels = 0; audio_decoder->HwSampleRate = 0; audio_decoder->HwChannels = 0; audio_decoder->LastDelay = 0; } /** ** Close audio decoder. ** ** @param audio_decoder private audio decoder */ void CodecAudioClose(AudioDecoder *audio_decoder) { // FIXME: output any buffered data #ifdef USE_SWRESAMPLE if (audio_decoder->Resample) { swr_free(&audio_decoder->Resample); } #endif #ifdef USE_AVRESAMPLE if (audio_decoder->Resample) { avresample_free(&audio_decoder->Resample); } #endif if (audio_decoder->AudioCtx) { pthread_mutex_lock(&CodecLockMutex); avcodec_close(audio_decoder->AudioCtx); av_freep(&audio_decoder->AudioCtx); pthread_mutex_unlock(&CodecLockMutex); } } /** ** Set audio drift correction. ** ** @param mask enable mask (PCM, AC-3) */ void CodecSetAudioDrift(int mask) { #ifdef USE_AUDIO_DRIFT_CORRECTION CodecAudioDrift = mask & (CORRECT_PCM | CORRECT_AC3); #endif (void)mask; } /** ** Set audio pass-through. ** ** @param mask enable mask (PCM, AC-3, E-AC-3) */ void CodecSetAudioPassthrough(int mask) { #ifdef USE_PASSTHROUGH CodecPassthrough = mask & (CodecPCM | CodecAC3 | CodecEAC3); #endif (void)mask; } /** ** Set audio downmix. ** ** @param onoff enable/disable downmix. */ void CodecSetAudioDownmix(int onoff) { if (onoff == -1) { CodecDownmix ^= 1; return; } CodecDownmix = onoff; } /** ** Reorder audio frame. ** ** ffmpeg L R C Ls Rs -> alsa L R Ls Rs C ** ffmpeg L R C LFE Ls Rs -> alsa L R Ls Rs C LFE ** ffmpeg L R C LFE Ls Rs Rl Rr -> alsa L R Ls Rs C LFE Rl Rr ** ** @param buf[IN,OUT] sample buffer ** @param size size of sample buffer in bytes ** @param channels number of channels interleaved in sample buffer */ static void CodecReorderAudioFrame(int16_t *buf, int size, int channels) { int i; int c; int ls; int rs; int lfe; switch (channels) { case 5: size /= 2; for (i = 0; i < size; i += 5) { c = buf[i + 2]; ls = buf[i + 3]; rs = buf[i + 4]; buf[i + 2] = ls; buf[i + 3] = rs; buf[i + 4] = c; } break; case 6: size /= 2; for (i = 0; i < size; i += 6) { c = buf[i + 2]; lfe = buf[i + 3]; ls = buf[i + 4]; rs = buf[i + 5]; buf[i + 2] = ls; buf[i + 3] = rs; buf[i + 4] = c; buf[i + 5] = lfe; } break; case 8: size /= 2; for (i = 0; i < size; i += 8) { c = buf[i + 2]; lfe = buf[i + 3]; ls = buf[i + 4]; rs = buf[i + 5]; buf[i + 2] = ls; buf[i + 3] = rs; buf[i + 4] = c; buf[i + 5] = lfe; } break; } } /** ** Handle audio format changes helper. ** ** @param audio_decoder audio decoder data ** @param[out] passthrough pass-through output */ static int CodecAudioUpdateHelper(AudioDecoder *audio_decoder, int *passthrough) { const AVCodecContext *audio_ctx; int err; audio_ctx = audio_decoder->AudioCtx; Debug(3, "codec/audio: format change %s %dHz *%d channels%s%s%s%s%s\n", av_get_sample_fmt_name(audio_ctx->sample_fmt), audio_ctx->sample_rate, audio_ctx->channels, CodecPassthrough & CodecPCM ? " PCM" : "", CodecPassthrough & CodecMPA ? " MPA" : "", CodecPassthrough & CodecAC3 ? " AC-3" : "", CodecPassthrough & CodecEAC3 ? " E-AC-3" : "", CodecPassthrough ? " pass-through" : ""); *passthrough = 0; audio_decoder->SampleRate = audio_ctx->sample_rate; audio_decoder->HwSampleRate = audio_ctx->sample_rate; audio_decoder->Channels = audio_ctx->channels; audio_decoder->HwChannels = audio_ctx->channels; audio_decoder->Passthrough = CodecPassthrough; // SPDIF/HDMI pass-through if ((CodecPassthrough & CodecAC3 && audio_ctx->codec_id == AV_CODEC_ID_AC3) || (CodecPassthrough & CodecEAC3 && audio_ctx->codec_id == AV_CODEC_ID_EAC3)) { if (audio_ctx->codec_id == AV_CODEC_ID_EAC3) { // E-AC-3 over HDMI some receivers need HBR audio_decoder->HwSampleRate *= 4; } audio_decoder->HwChannels = 2; audio_decoder->SpdifIndex = 0; // reset buffer audio_decoder->SpdifCount = 0; *passthrough = 1; } // channels/sample-rate not support? if ((err = AudioSetup(&audio_decoder->HwSampleRate, &audio_decoder->HwChannels, *passthrough))) { // try E-AC-3 none HBR audio_decoder->HwSampleRate /= 4; if (audio_ctx->codec_id != AV_CODEC_ID_EAC3 || (err = AudioSetup(&audio_decoder->HwSampleRate, &audio_decoder->HwChannels, *passthrough))) { Debug(3, "codec/audio: audio setup error\n"); // FIXME: handle errors audio_decoder->HwChannels = 0; audio_decoder->HwSampleRate = 0; return err; } } Debug(3, "codec/audio: resample %s %dHz *%d -> %s %dHz *%d\n", av_get_sample_fmt_name(audio_ctx->sample_fmt), audio_ctx->sample_rate, audio_ctx->channels, av_get_sample_fmt_name(AV_SAMPLE_FMT_S16), audio_decoder->HwSampleRate, audio_decoder->HwChannels); return 0; } /** ** Audio pass-through decoder helper. ** ** @param audio_decoder audio decoder data ** @param avpkt undecoded audio packet */ static int CodecAudioPassthroughHelper(AudioDecoder *audio_decoder, const AVPacket *avpkt) { #ifdef USE_PASSTHROUGH const AVCodecContext *audio_ctx; audio_ctx = audio_decoder->AudioCtx; // SPDIF/HDMI passthrough if (CodecPassthrough & CodecAC3 && audio_ctx->codec_id == AV_CODEC_ID_AC3) { uint16_t *spdif; int spdif_sz; spdif = audio_decoder->Spdif; spdif_sz = 6144; #ifdef USE_AC3_DRIFT_CORRECTION // FIXME: this works with some TVs/AVReceivers // FIXME: write burst size drift correction, which should work with all if (CodecAudioDrift & CORRECT_AC3) { int x; x = (audio_decoder->DriftFrac + (audio_decoder->DriftCorr * spdif_sz)) / (10 * audio_decoder->HwSampleRate * 100); audio_decoder->DriftFrac = (audio_decoder->DriftFrac + (audio_decoder->DriftCorr * spdif_sz)) % (10 * audio_decoder->HwSampleRate * 100); // round to word border x *= audio_decoder->HwChannels * 4; if (x < -64) { // limit correction x = -64; } else if (x > 64) { x = 64; } spdif_sz += x; } #endif // build SPDIF header and append A52 audio to it // avpkt is the original data if (spdif_sz < avpkt->size + 8) { Error(_("codec/audio: decoded data smaller than encoded\n")); return -1; } spdif[0] = htole16(0xF872); // iec 61937 sync word spdif[1] = htole16(0x4E1F); spdif[2] = htole16(IEC61937_AC3 | (avpkt->data[5] & 0x07) << 8); spdif[3] = htole16(avpkt->size * 8); // copy original data for output // FIXME: not 100% sure, if endian is correct on not intel hardware swab(avpkt->data, spdif + 4, avpkt->size); // FIXME: don't need to clear always memset(spdif + 4 + avpkt->size / 2, 0, spdif_sz - 8 - avpkt->size); // don't play with the ac-3 samples AudioEnqueue(spdif, spdif_sz); return 1; } if (CodecPassthrough & CodecEAC3 && audio_ctx->codec_id == AV_CODEC_ID_EAC3) { uint16_t *spdif; int spdif_sz; int repeat; // build SPDIF header and append A52 audio to it // avpkt is the original data spdif = audio_decoder->Spdif; spdif_sz = 24576; // 4 * 6144 if (audio_decoder->HwSampleRate == 48000) { spdif_sz = 6144; } if (spdif_sz < audio_decoder->SpdifIndex + avpkt->size + 8) { Error(_("codec/audio: decoded data smaller than encoded\n")); return -1; } // check if we must pack multiple packets repeat = 1; if ((avpkt->data[4] & 0xc0) != 0xc0) { // fscod static const uint8_t eac3_repeat[4] = {6, 3, 2, 1}; // fscod2 repeat = eac3_repeat[(avpkt->data[4] & 0x30) >> 4]; } // fprintf(stderr, "repeat %d %d\n", repeat, avpkt->size); // copy original data for output // pack upto repeat EAC-3 pakets into one IEC 61937 burst // FIXME: not 100% sure, if endian is correct on not intel hardware swab(avpkt->data, spdif + 4 + audio_decoder->SpdifIndex, avpkt->size); audio_decoder->SpdifIndex += avpkt->size; if (++audio_decoder->SpdifCount < repeat) { return 1; } spdif[0] = htole16(0xF872); // iec 61937 sync word spdif[1] = htole16(0x4E1F); spdif[2] = htole16(IEC61937_EAC3); spdif[3] = htole16(audio_decoder->SpdifIndex * 8); memset(spdif + 4 + audio_decoder->SpdifIndex / 2, 0, spdif_sz - 8 - audio_decoder->SpdifIndex); // don't play with the eac-3 samples AudioEnqueue(spdif, spdif_sz); audio_decoder->SpdifIndex = 0; audio_decoder->SpdifCount = 0; return 1; } #endif return 0; } #if defined(USE_SWRESAMPLE) || defined(USE_AVRESAMPLE) /** ** Set/update audio pts clock. ** ** @param audio_decoder audio decoder data ** @param pts presentation timestamp */ static void CodecAudioSetClock(AudioDecoder *audio_decoder, int64_t pts) { #ifdef USE_AUDIO_DRIFT_CORRECTION struct timespec nowtime; int64_t delay; int64_t tim_diff; int64_t pts_diff; int drift; int corr; AudioSetClock(pts); delay = AudioGetDelay(); if (!delay) { return; } clock_gettime(CLOCK_MONOTONIC, &nowtime); if (!audio_decoder->LastDelay) { audio_decoder->LastTime = nowtime; audio_decoder->LastPTS = pts; audio_decoder->LastDelay = delay; audio_decoder->Drift = 0; audio_decoder->DriftFrac = 0; Debug(3, "codec/audio: inital drift delay %" PRId64 "ms\n", delay / 90); return; } // collect over some time pts_diff = pts - audio_decoder->LastPTS; if (pts_diff < 10 * 1000 * 90) { return; } tim_diff = (nowtime.tv_sec - audio_decoder->LastTime.tv_sec) * 1000 * 1000 * 1000 + (nowtime.tv_nsec - audio_decoder->LastTime.tv_nsec); drift = (tim_diff * 90) / (1000 * 1000) - pts_diff + delay - audio_decoder->LastDelay; // adjust rounding error nowtime.tv_nsec -= nowtime.tv_nsec % (1000 * 1000 / 90); audio_decoder->LastTime = nowtime; audio_decoder->LastPTS = pts; audio_decoder->LastDelay = delay; if (0) { Debug(3, "codec/audio: interval P:%5" PRId64 "ms T:%5" PRId64 "ms D:%4" PRId64 "ms %f %d\n", pts_diff / 90, tim_diff / (1000 * 1000), delay / 90, drift / 90.0, audio_decoder->DriftCorr); } // underruns and av_resample have the same time :((( if (abs(drift) > 10 * 90) { // drift too big, pts changed? Debug(3, "codec/audio: drift(%6d) %3dms reset\n", audio_decoder->DriftCorr, drift / 90); audio_decoder->LastDelay = 0; #ifdef DEBUG corr = 0; // keep gcc happy #endif } else { drift += audio_decoder->Drift; audio_decoder->Drift = drift; corr = (10 * audio_decoder->HwSampleRate * drift) / (90 * 1000); // SPDIF/HDMI passthrough if ((CodecAudioDrift & CORRECT_AC3) && (!(CodecPassthrough & CodecAC3) || audio_decoder->AudioCtx->codec_id != AV_CODEC_ID_AC3) && (!(CodecPassthrough & CodecEAC3) || audio_decoder->AudioCtx->codec_id != AV_CODEC_ID_EAC3)) { audio_decoder->DriftCorr = -corr; } if (audio_decoder->DriftCorr < -20000) { // limit correction audio_decoder->DriftCorr = -20000; } else if (audio_decoder->DriftCorr > 20000) { audio_decoder->DriftCorr = 20000; } } #ifdef USE_SWRESAMPLE if (audio_decoder->Resample && audio_decoder->DriftCorr) { int distance; // try workaround for buggy ffmpeg 0.10 if (abs(audio_decoder->DriftCorr) < 2000) { distance = (pts_diff * audio_decoder->HwSampleRate) / (900 * 1000); } else { distance = (pts_diff * audio_decoder->HwSampleRate) / (90 * 1000); } if (swr_set_compensation(audio_decoder->Resample, audio_decoder->DriftCorr / 10, distance)) { Debug(3, "codec/audio: swr_set_compensation failed\n"); } } #endif #ifdef USE_AVRESAMPLE if (audio_decoder->Resample && audio_decoder->DriftCorr) { int distance; distance = (pts_diff * audio_decoder->HwSampleRate) / (900 * 1000); if (avresample_set_compensation(audio_decoder->Resample, audio_decoder->DriftCorr / 10, distance)) { Debug(3, "codec/audio: swr_set_compensation failed\n"); } } #endif if (1) { static int c; if (!(c++ % 10)) { Debug(3, "codec/audio: drift(%6d) %8dus %5d\n", audio_decoder->DriftCorr, drift * 1000 / 90, corr); } } #else AudioSetClock(pts); #endif } /** ** Handle audio format changes. ** ** @param audio_decoder audio decoder data */ static void CodecAudioUpdateFormat(AudioDecoder *audio_decoder) { int passthrough; const AVCodecContext *audio_ctx; if (CodecAudioUpdateHelper(audio_decoder, &passthrough)) { // FIXME: handle swresample format conversions. return; } if (passthrough) { // pass-through no conversion allowed return; } audio_ctx = audio_decoder->AudioCtx; #ifdef DEBUG if (audio_ctx->sample_fmt == AV_SAMPLE_FMT_S16 && audio_ctx->sample_rate == audio_decoder->HwSampleRate && !CodecAudioDrift) { // FIXME: use Resample only, when it is needed! fprintf(stderr, "no resample needed\n"); } #endif #ifdef USE_SWRESAMPLE audio_decoder->Resample = swr_alloc_set_opts(audio_decoder->Resample, audio_ctx->channel_layout, AV_SAMPLE_FMT_S16, audio_decoder->HwSampleRate, audio_ctx->channel_layout, audio_ctx->sample_fmt, audio_ctx->sample_rate, 0, NULL); if (audio_decoder->Resample) { swr_init(audio_decoder->Resample); } else { Error(_("codec/audio: can't setup resample\n")); } #endif #ifdef USE_AVRESAMPLE if (!(audio_decoder->Resample = avresample_alloc_context())) { Error(_("codec/audio: can't setup resample\n")); return; } av_opt_set_int(audio_decoder->Resample, "in_channel_layout", audio_ctx->channel_layout, 0); av_opt_set_int(audio_decoder->Resample, "in_sample_fmt", audio_ctx->sample_fmt, 0); av_opt_set_int(audio_decoder->Resample, "in_sample_rate", audio_ctx->sample_rate, 0); av_opt_set_int(audio_decoder->Resample, "out_channel_layout", audio_ctx->channel_layout, 0); av_opt_set_int(audio_decoder->Resample, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); av_opt_set_int(audio_decoder->Resample, "out_sample_rate", audio_decoder->HwSampleRate, 0); if (avresample_open(audio_decoder->Resample)) { avresample_free(&audio_decoder->Resample); audio_decoder->Resample = NULL; Error(_("codec/audio: can't open resample\n")); return; } #endif } /** ** Decode an audio packet. ** ** PTS must be handled self. ** ** @note the caller has not aligned avpkt and not cleared the end. ** ** @param audio_decoder audio decoder data ** @param avpkt audio packet */ void CodecAudioDecode(AudioDecoder *audio_decoder, const AVPacket *avpkt) { AVCodecContext *audio_ctx = audio_decoder->AudioCtx; if (audio_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { int ret; AVPacket pkt[1]; AVFrame *frame = audio_decoder->Frame; av_frame_unref(frame); *pkt = *avpkt; // use copy ret = avcodec_send_packet(audio_ctx, pkt); if (ret < 0) { Debug(3, "codec: sending audio packet failed"); return; } ret = avcodec_receive_frame(audio_ctx, frame); if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { Debug(3, "codec: receiving audio frame failed"); return; } if (ret >= 0) { // update audio clock if (avpkt->pts != (int64_t)AV_NOPTS_VALUE) { CodecAudioSetClock(audio_decoder, avpkt->pts); } // format change if (audio_decoder->Passthrough != CodecPassthrough || audio_decoder->SampleRate != audio_ctx->sample_rate || audio_decoder->Channels != audio_ctx->channels) { CodecAudioUpdateFormat(audio_decoder); } if (!audio_decoder->HwSampleRate || !audio_decoder->HwChannels) { return; // unsupported sample format } if (CodecAudioPassthroughHelper(audio_decoder, avpkt)) { return; } if (audio_decoder->Resample) { uint8_t outbuf[8192 * 2 * 8]; uint8_t *out[1]; out[0] = outbuf; ret = swr_convert(audio_decoder->Resample, out, sizeof(outbuf) / (2 * audio_decoder->HwChannels), (const uint8_t **)frame->extended_data, frame->nb_samples); if (ret > 0) { if (!(audio_decoder->Passthrough & CodecPCM)) { CodecReorderAudioFrame((int16_t *)outbuf, ret * 2 * audio_decoder->HwChannels, audio_decoder->HwChannels); } AudioEnqueue(outbuf, ret * 2 * audio_decoder->HwChannels); } return; } } } } #endif /** ** Flush the audio decoder. ** ** @param decoder audio decoder data */ void CodecAudioFlushBuffers(AudioDecoder *decoder) { avcodec_flush_buffers(decoder->AudioCtx); } //---------------------------------------------------------------------------- // Codec //---------------------------------------------------------------------------- /** ** Empty log callback */ static void CodecNoopCallback(__attribute__((unused)) void *ptr, __attribute__((unused)) int level, __attribute__((unused)) const char *fmt, __attribute__((unused)) va_list vl) {} /** ** Codec init */ void CodecInit(void) { pthread_mutex_init(&CodecLockMutex, NULL); #ifndef DEBUG // disable display ffmpeg error messages av_log_set_callback(CodecNoopCallback); #else (void)CodecNoopCallback; #endif } /** ** Codec exit. */ void CodecExit(void) { pthread_mutex_destroy(&CodecLockMutex); }