Ticket #10745: h264reset.patch

File h264reset.patch, 14.6 KB (added by JYA, 12 years ago)

This patch close the h264 decoder and re-open it if a change of resolution is detected

  • mythtv/libs/libmythtv/avformatdecoder.cpp

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index 832500b..c9d8923 100644
    a b int AvFormatDecoder::ScanStreams(bool novideo) 
    20292029            continue;
    20302030        }
    20312031
    2032         AVCodec *codec = avcodec_find_decoder(enc->codec_id);
    2033         if (!codec)
    2034         {
    2035             LOG(VB_GENERAL, LOG_ERR, LOC +
    2036                 QString("Could not find decoder for codec (%1), ignoring.")
    2037                     .arg(ff_codec_id_string(enc->codec_id)));
    2038 
    2039             // Nigel's bogus codec-debug. Dump the list of codecs & decoders,
    2040             // and have one last attempt to find a decoder. This is usually
    2041             // only caused by build problems, where libavcodec needs a rebuild
    2042             if (VERBOSE_LEVEL_CHECK(VB_LIBAV, LOG_ANY))
    2043             {
    2044                 AVCodec *p = av_codec_next(NULL);
    2045                 int      i = 1;
    2046                 while (p)
    2047                 {
    2048                     QString msg;
    2049 
    2050                     if (p->name[0] != '\0')
    2051                         msg = QString("Codec %1:").arg(p->name);
    2052                     else
    2053                         msg = QString("Codec %1, null name,").arg(i);
    2054 
    2055                     if (p->decode == NULL)
    2056                         msg += "decoder is null";
    2057 
    2058                     LOG(VB_LIBAV, LOG_INFO, LOC + msg);
    2059 
    2060                     if (p->id == enc->codec_id)
    2061                     {
    2062                         codec = p;
    2063                         break;
    2064                     }
    2065 
    2066                     LOG(VB_LIBAV, LOG_INFO, LOC +
    2067                         QString("Codec 0x%1 != 0x%2") .arg(p->id, 0, 16)
    2068                             .arg(enc->codec_id, 0, 16));
    2069                     p = av_codec_next(p);
    2070                     ++i;
    2071                 }
    2072             }
    2073             if (!codec)
    2074                 continue;
    2075         }
    2076         // select vdpau capable decoder if needed
    2077         else if (enc->codec_type == AVMEDIA_TYPE_VIDEO &&
    2078                  codec_is_vdpau(video_codec_id) && !CODEC_IS_VDPAU(codec))
    2079         {
    2080             codec = find_vdpau_decoder(codec, enc->codec_id);
    2081         }
    2082 
    2083         if (!enc->codec)
     2032        if (!InitCodec(enc, i,
     2033                         &lang_sub_cnt, &subtitleStreamCount,
     2034                         &lang_aud_cnt, &audioStreamCount))
    20842035        {
    2085             QMutexLocker locker(avcodeclock);
    2086 
    2087             int open_val = avcodec_open2(enc, codec, NULL);
    2088             if (open_val < 0)
    2089             {
    2090                 LOG(VB_GENERAL, LOG_ERR, LOC +
    2091                     QString("Could not open codec 0x%1, id(%2) type(%3) "
    2092                             "aborting. reason %4").arg((uint64_t)enc,0,16)
    2093                         .arg(ff_codec_id_string(enc->codec_id))
    2094                         .arg(ff_codec_type_string(enc->codec_type))
    2095                         .arg(open_val));
    2096                 //av_close_input_file(ic); // causes segfault
    2097                 ic = NULL;
    2098                 scanerror = -1;
    2099                 break;
    2100             }
    2101             else
    2102             {
    2103                 LOG(VB_GENERAL, LOG_INFO, LOC +
    2104                     QString("Opened codec 0x%1, id(%2) type(%3)")
    2105                         .arg((uint64_t)enc,0,16)
    2106                         .arg(ff_codec_id_string(enc->codec_id))
    2107                         .arg(ff_codec_type_string(enc->codec_type)));
    2108             }
    2109         }
    2110 
    2111         if (enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
    2112         {
    2113             bool forced = ic->streams[i]->disposition & AV_DISPOSITION_FORCED;
    2114             int lang = GetSubtitleLanguage(subtitleStreamCount, i);
    2115             int lang_indx = lang_sub_cnt[lang]++;
    2116             subtitleStreamCount++;
    2117 
    2118             tracks[kTrackTypeSubtitle].push_back(
    2119                 StreamInfo(i, lang, lang_indx, ic->streams[i]->id, 0, 0, false, false, forced));
    2120 
    2121             LOG(VB_PLAYBACK, LOG_INFO, LOC +
    2122                 QString("Subtitle track #%1 is A/V stream #%2 "
    2123                         "and is in the %3 language(%4).")
    2124                     .arg(tracks[kTrackTypeSubtitle].size()).arg(i)
    2125                     .arg(iso639_key_toName(lang)).arg(lang));
    2126         }
    2127 
    2128         if (enc->codec_type == AVMEDIA_TYPE_AUDIO)
    2129         {
    2130             int lang = GetAudioLanguage(audioStreamCount, i);
    2131             int channels  = ic->streams[i]->codec->channels;
    2132             int lang_indx = lang_aud_cnt[lang]++;
    2133             audioStreamCount++;
    2134             AudioTrackType type = kAudioTypeNormal;
    2135 
    2136             if (ic->streams[i]->codec->avcodec_dual_language)
    2137             {
    2138                 tracks[kTrackTypeAudio].push_back(
    2139                     StreamInfo(i, lang, lang_indx, ic->streams[i]->id, channels,
    2140                                false, false, false, type));
    2141                 lang_indx = lang_aud_cnt[lang]++;
    2142                 tracks[kTrackTypeAudio].push_back(
    2143                     StreamInfo(i, lang, lang_indx, ic->streams[i]->id, channels,
    2144                                true, false, false, type));
    2145             }
    2146             else
    2147             {
    2148                 int logical_stream_id;
    2149                 if (ringBuffer && ringBuffer->IsDVD())
    2150                 {
    2151                     logical_stream_id =
    2152                         ringBuffer->DVD()->GetAudioTrackNum(ic->streams[i]->id);
    2153                     type = (AudioTrackType)(ringBuffer->DVD()->GetAudioTrackType(ic->streams[i]->id));
    2154                 }
    2155                 else
    2156                     logical_stream_id = ic->streams[i]->id;
    2157 
    2158                 tracks[kTrackTypeAudio].push_back(
    2159                    StreamInfo(i, lang, lang_indx, logical_stream_id, channels,
    2160                               false, false, false, type));
    2161             }
    2162 
    2163             LOG(VB_AUDIO, LOG_INFO, LOC +
    2164                 QString("Audio Track #%1, with type %2 is A/V stream #%3 "
    2165                         "and has %4 channels in the %5 language(%6).")
    2166                     .arg(tracks[kTrackTypeAudio].size()).arg((int)type).arg(i)
    2167                     .arg(enc->channels)
    2168                     .arg(iso639_key_toName(lang)).arg(lang));
     2036            scanerror = -1;
     2037            break;
    21692038        }
    21702039    }
    21712040
    int AvFormatDecoder::ScanStreams(bool novideo) 
    22262095    return scanerror;
    22272096}
    22282097
     2098bool AvFormatDecoder::InitCodec(AVCodecContext *enc, int currentstream,
     2099                                  map<int,uint> *lang_sub_cnt,
     2100                                  uint *subtitleStreamCount,
     2101                                  map<int,uint> *lang_aud_cnt,
     2102                                  uint *audioStreamCount)
     2103{
     2104    AVCodec *codec = avcodec_find_decoder(enc->codec_id);
     2105    if (!codec)
     2106    {
     2107        LOG(VB_GENERAL, LOG_ERR, LOC +
     2108            QString("Could not find decoder for codec (%1), ignoring.")
     2109            .arg(ff_codec_id_string(enc->codec_id)));
     2110
     2111        // Nigel's bogus codec-debug. Dump the list of codecs & decoders,
     2112        // and have one last attempt to find a decoder. This is usually
     2113        // only caused by build problems, where libavcodec needs a rebuild
     2114        if (VERBOSE_LEVEL_CHECK(VB_LIBAV, LOG_ANY))
     2115        {
     2116            AVCodec *p = av_codec_next(NULL);
     2117            int      i = 1;
     2118            while (p)
     2119            {
     2120                QString msg;
     2121
     2122                if (p->name[0] != '\0')
     2123                    msg = QString("Codec %1:").arg(p->name);
     2124                else
     2125                    msg = QString("Codec %1, null name,").arg(i);
     2126
     2127                if (p->decode == NULL)
     2128                    msg += "decoder is null";
     2129
     2130                LOG(VB_LIBAV, LOG_INFO, LOC + msg);
     2131
     2132                if (p->id == enc->codec_id)
     2133                {
     2134                    codec = p;
     2135                    break;
     2136                }
     2137
     2138                LOG(VB_LIBAV, LOG_INFO, LOC +
     2139                    QString("Codec 0x%1 != 0x%2") .arg(p->id, 0, 16)
     2140                    .arg(enc->codec_id, 0, 16));
     2141                p = av_codec_next(p);
     2142                ++i;
     2143            }
     2144        }
     2145        if (!codec)
     2146            return true;
     2147    }
     2148    // select vdpau capable decoder if needed
     2149    else if (enc->codec_type == AVMEDIA_TYPE_VIDEO &&
     2150             codec_is_vdpau(video_codec_id) && !CODEC_IS_VDPAU(codec))
     2151    {
     2152        codec = find_vdpau_decoder(codec, enc->codec_id);
     2153    }
     2154
     2155    if (!enc->codec)
     2156    {
     2157        QMutexLocker locker(avcodeclock);
     2158
     2159        int open_val = avcodec_open2(enc, codec, NULL);
     2160        if (open_val < 0)
     2161        {
     2162            LOG(VB_GENERAL, LOG_ERR, LOC +
     2163                QString("Could not open codec 0x%1, id(%2) type(%3) "
     2164                        "aborting. reason %4").arg((uint64_t)enc,0,16)
     2165                .arg(ff_codec_id_string(enc->codec_id))
     2166                .arg(ff_codec_type_string(enc->codec_type))
     2167                .arg(open_val));
     2168            //av_close_input_file(ic); // causes segfault
     2169            ic = NULL;
     2170            return false;
     2171        }
     2172        else
     2173        {
     2174            LOG(VB_GENERAL, LOG_INFO, LOC +
     2175                QString("Opened codec 0x%1, id(%2) type(%3)")
     2176                .arg((uint64_t)enc,0,16)
     2177                .arg(ff_codec_id_string(enc->codec_id))
     2178                .arg(ff_codec_type_string(enc->codec_type)));
     2179        }
     2180    }
     2181
     2182    if (enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
     2183    {
     2184        bool forced = ic->streams[currentstream]->disposition & AV_DISPOSITION_FORCED;
     2185        int lang = GetSubtitleLanguage(*subtitleStreamCount, currentstream);
     2186        int lang_indx = (*lang_sub_cnt)[lang]++;
     2187        *subtitleStreamCount++;
     2188
     2189        tracks[kTrackTypeSubtitle].push_back(
     2190            StreamInfo(currentstream, lang, lang_indx,
     2191                       ic->streams[currentstream]->id, 0,
     2192                       0, false, false, forced));
     2193
     2194        LOG(VB_PLAYBACK, LOG_INFO, LOC +
     2195            QString("Subtitle track #%1 is A/V stream #%2 "
     2196                    "and is in the %3 language(%4).")
     2197            .arg(tracks[kTrackTypeSubtitle].size()).arg(currentstream)
     2198            .arg(iso639_key_toName(lang)).arg(lang));
     2199    }
     2200
     2201    if (enc->codec_type == AVMEDIA_TYPE_AUDIO)
     2202    {
     2203        int lang = GetAudioLanguage(*audioStreamCount, currentstream);
     2204        int channels  = ic->streams[currentstream]->codec->channels;
     2205        int lang_indx = (*lang_aud_cnt)[lang]++;
     2206        *audioStreamCount++;
     2207        AudioTrackType type = kAudioTypeNormal;
     2208
     2209        if (ic->streams[currentstream]->codec->avcodec_dual_language)
     2210        {
     2211            tracks[kTrackTypeAudio].push_back(
     2212                StreamInfo(currentstream, lang, lang_indx,
     2213                           ic->streams[currentstream]->id, channels,
     2214                           false, false, false, type));
     2215            lang_indx = (*lang_aud_cnt)[lang]++;
     2216            tracks[kTrackTypeAudio].push_back(
     2217                StreamInfo(currentstream, lang, lang_indx,
     2218                           ic->streams[currentstream]->id, channels,
     2219                           true, false, false, type));
     2220        }
     2221        else
     2222        {
     2223            int logical_stream_id;
     2224            if (ringBuffer && ringBuffer->IsDVD())
     2225            {
     2226                logical_stream_id =
     2227                    ringBuffer->DVD()->GetAudioTrackNum(ic->streams[currentstream]->id);
     2228                type =
     2229                    (AudioTrackType)(ringBuffer->DVD()->GetAudioTrackType(ic->streams[currentstream]->id));
     2230            }
     2231            else
     2232                logical_stream_id = ic->streams[currentstream]->id;
     2233
     2234            tracks[kTrackTypeAudio].push_back(
     2235                StreamInfo(currentstream, lang, lang_indx, logical_stream_id,
     2236                           channels, false, false, false, type));
     2237        }
     2238
     2239        LOG(VB_AUDIO, LOG_INFO, LOC +
     2240            QString("Audio Track #%1, with type %2 is A/V stream #%3 "
     2241                    "and has %4 channels in the %5 language(%6).")
     2242            .arg(tracks[kTrackTypeAudio].size()).arg((int)type).arg(currentstream)
     2243            .arg(enc->channels)
     2244            .arg(iso639_key_toName(lang)).arg(lang));
     2245    }
     2246    return true;
     2247}
     2248
    22292249void AvFormatDecoder::UpdateFramesPlayed(void)
    22302250{
    22312251    return DecoderBase::UpdateFramesPlayed();
    bool AvFormatDecoder::H264PreProcessPkt(AVStream *stream, AVPacket *pkt) 
    29482968        uint  width  = dim.width();
    29492969        uint  height = dim.height();
    29502970        float seqFPS = normalized_fps(stream, context);
     2971        bool waszero = !(width && height && current_width && current_height);
    29512972
    29522973        bool changed = (seqFPS > fps+0.01f) || (seqFPS < fps-0.01f);
    29532974        changed |= (width  != (uint)current_width );
    bool AvFormatDecoder::H264PreProcessPkt(AVStream *stream, AVPacket *pkt) 
    29793000                    QString("avFPS(%1) != seqFPS(%2)")
    29803001                        .arg(avFPS).arg(seqFPS));
    29813002            }
     3003
     3004            // FFmpeg HACK:
     3005            // resolution was changed ; ffmpeg H264 decoder doesn't handle it
     3006            // properly. So close and re-open decoder
     3007            if (!waszero)
     3008            {
     3009                LOG(VB_PLAYBACK, LOG_INFO, LOC + "resetting H264 decoder");
     3010                QMutexLocker locker(avcodeclock);
     3011                if (stream->codec->codec)
     3012                    avcodec_close(stream->codec);
     3013                InitCodec(stream->codec);
     3014            }
    29823015        }
    29833016
    29843017        HandleGopStart(pkt, true);
  • mythtv/libs/libmythtv/avformatdecoder.h

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h
    index aa3f9d1..0a650db 100644
    a b class AvFormatDecoder : public DecoderBase 
    105105
    106106    /// Perform an av_probe_input_format on the passed data to see if we
    107107    /// can decode it with this class.
    108     static bool CanHandle(char testbuf[kDecoderProbeBufferSize], 
     108    static bool CanHandle(char testbuf[kDecoderProbeBufferSize],
    109109                          const QString &filename,
    110110                          int testbufsize = kDecoderProbeBufferSize);
    111111
    112112    /// Open our file and set up or audio and video parameters.
    113     int OpenFile(RingBuffer *rbuffer, bool novideo, 
     113    int OpenFile(RingBuffer *rbuffer, bool novideo,
    114114                 char testbuf[kDecoderProbeBufferSize],
    115115                 int testbufsize = kDecoderProbeBufferSize);
    116116
    class AvFormatDecoder : public DecoderBase 
    152152    virtual int SetTrack(uint type, int trackNo);
    153153
    154154    int ScanStreams(bool novideo);
     155    bool InitCodec(AVCodecContext *enc, int currentstream = 0,
     156                     map<int,uint> *lang_sub_cnt = NULL,
     157                     uint *subtitleStreamCount = NULL,
     158                     map<int,uint> *lang_aud_cnt = NULL,
     159                     uint *audioStreamCount = NULL);
    155160    int FindStreamInfo(void);
    156161
    157162    virtual int  GetNumChapters();