Ticket #2439: language_04_myth_0_20_patch.txt

File language_04_myth_0_20_patch.txt, 16.2 KB (added by szermatt@…, 13 years ago)

language4_0.20.patch

Line 
1Index: libs/libmythtv/decoderbase.h
2===================================================================
3--- libs/libmythtv/decoderbase.h        (revision 11213)
4+++ libs/libmythtv/decoderbase.h        (working copy)
5@@ -21,13 +21,18 @@
6         stream_id(-1), easy_reader(false), wide_aspect_ratio(false) {}
7     StreamInfo(int a, int b, uint c, int d, bool e = false, bool f = false) :
8         av_stream_index(a), language(b), language_index(c), stream_id(d),
9-        easy_reader(e), wide_aspect_ratio(f) {}
10+        av_substream_index(-1), easy_reader(e), wide_aspect_ratio(f) {}
11+    // Audio stream/substream constructor
12+    StreamInfo(int a, int b, uint c, int d, int e) :
13+        av_stream_index(a), language(b), language_index(c), stream_id(d),
14+        av_substream_index(e), easy_reader(false), wide_aspect_ratio(false) {}
15 
16   public:
17     int  av_stream_index;
18     int  language; ///< ISO639 canonical language key
19     uint language_index;
20     int  stream_id;
21+    int  av_substream_index; // -1 = no substream, 0 for first dual audio stream
22     bool easy_reader;
23     bool wide_aspect_ratio;
24 
25Index: libs/libmythtv/avformatdecoder.cpp
26===================================================================
27--- libs/libmythtv/avformatdecoder.cpp  (revision 11213)
28+++ libs/libmythtv/avformatdecoder.cpp  (working copy)
29@@ -1468,8 +1468,18 @@
30                 lang_indx = lang_aud_cnt[lang];
31                 lang_aud_cnt[lang]++;
32             }
33-            tracks[kTrackTypeAudio].push_back(
34-                StreamInfo(i, lang, lang_indx, ic->streams[i]->id));
35+            if (ic->streams[i]->codec->avcodec_dual_language)
36+            {
37+                tracks[kTrackTypeAudio].push_back(
38+                    StreamInfo(i, lang, lang_indx, ic->streams[i]->id, 0));
39+                tracks[kTrackTypeAudio].push_back(
40+                    StreamInfo(i, lang, lang_indx, ic->streams[i]->id, 1));
41+            }
42+            else
43+            {
44+                tracks[kTrackTypeAudio].push_back(
45+                    StreamInfo(i, lang, lang_indx, ic->streams[i]->id));
46+            }
47 
48             VERBOSE(VB_AUDIO, LOC + QString(
49                         "Audio Track #%1 is A/V stream #%2 "
50@@ -1533,6 +1543,64 @@
51     return scanerror;
52 }
53 
54+/** \fn AvFormatDecoder::FixAudioStreamSubIndexes(bool, bool)
55+ *  \brief Reacts to DUAL/STEREO changes on the fly and fix streams.
56+ *
57+ *  This function kicks in when a switch between dual and stereo
58+ *  mpeg audio is detected. Such changes can and will happen at
59+ *  any time.
60+ *
61+ *  It can only be used in the case where the mpeg file contains
62+ *  exactly one audio stream that switches automatically between
63+ *  stereo (1 language) and dual (2 unspecified languages) audio.
64+ *
65+ *  If this method returns true, the stream list has changed and
66+ *  a new audio stream needs to be selected, usually using
67+ *  AvFormatDecoder::autoSelectSubtitleTrack()
68+ *
69+ *  \param wasDual true if the stream used to contain dual audio
70+ *  \param isDual true if the stream currently contains dual audio
71+ *  \return true if a change was made
72+ */
73+bool AvFormatDecoder::FixAudioStreamSubIndexes(bool wasDual, bool isDual)
74+{
75+    if (wasDual == isDual)
76+    {
77+        // No changes
78+        return false;
79+    }
80+
81+    QMutexLocker locker(&avcodeclock);
82+    int numStreams = tracks[kTrackTypeAudio].size();
83+    if (isDual)
84+    {
85+        assert(numStreams == 1);
86+
87+        // When assertions are off: ignore change
88+        if (numStreams != 1)
89+            return false;
90+
91+        // Split stream in two (Language I + Language II)
92+        tracks[kTrackTypeAudio].push_back(tracks[kTrackTypeAudio][0]);
93+        tracks[kTrackTypeAudio][0].av_substream_index = 0;
94+        tracks[kTrackTypeAudio][1].av_substream_index = 1;
95+    }
96+    else
97+    {
98+        assert(numStreams == 2);
99+
100+        if (numStreams != 2)
101+            return false;
102+
103+        // Remove extra stream
104+        tracks[kTrackTypeAudio][0].av_substream_index = -1;
105+        tracks[kTrackTypeAudio].pop_back();
106+    }
107+
108+    // Changed
109+    return true;
110+}
111+
112 int get_avf_buffer(struct AVCodecContext *c, AVFrame *pic)
113 {
114     AvFormatDecoder *nd = (AvFormatDecoder *)(c->opaque);
115@@ -2346,7 +2414,9 @@
116  *   preference:
117  *
118  *   1) The stream last selected by the user, which is
119- *      recalled as the Nth stream in the preferred language.
120+ *      recalled as the Nth stream in the preferred language
121+ *      or the Nth substream when audio is in dual language
122+ *      format (each channel contains a different language track)
123  *      If it can not be located we attempt to find a stream
124  *      in the same language.
125  *
126@@ -2413,6 +2483,24 @@
127     int selTrack = (1 == numStreams) ? 0 : -1;
128     int wlang    = wtrack.language;
129 
130+
131+    if (selTrack < 0 && wtrack.av_substream_index >=0)
132+    {
133+        VERBOSE(VB_AUDIO, LOC + "Trying to reselect audio sub-stream");
134+        // Dual stream without language information: choose
135+        // the previous (sub)stream that was kept in wtrack.
136+        int substream_index = wtrack.av_substream_index;
137+
138+        for (uint i = 0; i < numStreams; i++)
139+        {
140+            if (atracks[i].av_substream_index == substream_index)
141+            {
142+                selTrack = i;
143+                break;
144+            }
145+        }
146+    }
147+
148     if ((selTrack < 0) && wlang >= -1 && numStreams)
149     {
150         VERBOSE(VB_AUDIO, LOC + "Trying to reselect audio track");
151@@ -2493,6 +2581,40 @@
152     return selTrack;
153 }
154 
155+static void filter_audio_data(int channel, AudioInfo* audioInfo,
156+                              char *buffer, int bufsize)
157+{
158+    // Only stereo -> mono (left or right) is supported
159+    assert(audioInfo->channels == 2);
160+    assert(channel == 0 || channel == 1);
161+
162+    const int samplesize = audioInfo->sample_size;
163+    const int samples = bufsize / samplesize;
164+    const int halfsample = samplesize/2;
165+
166+    const char *from;
167+    char *to;
168+
169+    if (channel==0)
170+    {
171+        from=buffer;
172+        to=buffer+halfsample;
173+    }
174+    else
175+    {
176+        from=buffer+halfsample;
177+        to=buffer;
178+    }
179+
180+    for (int sample = 0; sample < samples;
181+         sample++, from += samplesize, to += samplesize)
182+    {
183+        for(int bit=0; bit < halfsample; bit++)
184+            to[bit]=from[bit];
185+    }
186+}
187+
188+
189 bool AvFormatDecoder::GetFrame(int onlyvideo)
190 {
191     AVPacket *pkt = NULL;
192@@ -2761,6 +2883,7 @@
193         avcodeclock.lock();
194         int ctype  = curstream->codec->codec_type;
195         int audIdx = selectedTrack[kTrackTypeAudio].av_stream_index;
196+        int audSubIdx = selectedTrack[kTrackTypeAudio].av_substream_index;
197         int subIdx = selectedTrack[kTrackTypeSubtitle].av_stream_index;
198         avcodeclock.unlock();
199 
200@@ -2770,6 +2893,15 @@
201             {
202                 case CODEC_TYPE_AUDIO:
203                 {
204+                    bool reselectAudioTrack = false;
205+
206+                    // detect switches between stereo and dual languages
207+                    if (FixAudioStreamSubIndexes(audSubIdx != -1,
208+                                                 curstream->codec->avcodec_dual_language))
209+                    {
210+                        reselectAudioTrack = true;
211+                    }
212+
213                     // detect channels on streams that need
214                     // to be decoded before we can know this
215                     if (!curstream->codec->channels)
216@@ -2781,16 +2913,26 @@
217                             &data_size, ptr, len);
218                         if (curstream->codec->channels)
219                         {
220-                            currentTrack[kTrackTypeAudio] = -1;
221-                            selectedTrack[kTrackTypeAudio]
222-                                .av_stream_index = -1;
223-                            audIdx = -1;
224-                            AutoSelectAudioTrack();
225-                            audIdx = selectedTrack[kTrackTypeAudio]
226-                                .av_stream_index;
227+                            reselectAudioTrack = true;
228                         }
229                     }
230 
231+                    if (reselectAudioTrack)
232+                    {
233+                        QMutexLocker locker(&avcodeclock);
234+                        currentTrack[kTrackTypeAudio] = -1;
235+                        selectedTrack[kTrackTypeAudio]
236+                            .av_stream_index = -1;
237+                        audIdx = -1;
238+                        audSubIdx = -1;
239+                        AutoSelectAudioTrack();
240+                        audIdx = selectedTrack[kTrackTypeAudio]
241+                            .av_stream_index;
242+                        audSubIdx = selectedTrack[kTrackTypeAudio]
243+                            .av_substream_index;
244+                    }
245+
246+
247                     if (firstloop && pkt->pts != (int64_t)AV_NOPTS_VALUE)
248                         lastapts = (long long)(av_q2d(curstream->time_base) *
249                                                pkt->pts * 1000);
250@@ -2873,6 +3015,11 @@
251                             .arg(pkt->pts).arg(pkt->dts).arg(temppts)
252                                                        .arg(lastapts));
253 
254+                    if (audSubIdx != -1)
255+                    {
256+                        filter_audio_data(audSubIdx, &audioOut,
257+                                          (char *)audioSamples, data_size);
258+                    }
259                     GetNVP()->AddAudioData((char *)audioSamples, data_size,
260                                            temppts);
261 
262Index: libs/libmythtv/mpegrecorder.h
263===================================================================
264--- libs/libmythtv/mpegrecorder.h       (revision 11213)
265+++ libs/libmythtv/mpegrecorder.h       (working copy)
266@@ -77,6 +77,7 @@
267     int bitrate, maxbitrate, streamtype, aspectratio;
268     int audtype, audsamplerate, audbitratel1, audbitratel2;
269     int audvolume;
270+    int language;
271 
272     // Input file descriptors
273     int chanfd;
274@@ -101,6 +102,7 @@
275 
276     static const int   audRateL1[];
277     static const int   audRateL2[];
278+    static const char* languages[];
279     static const char *streamType[];
280     static const char *aspectRatio[];
281     static const unsigned int kBuildBufferMaxSize;
282Index: libs/libmythtv/avformatdecoder.h
283===================================================================
284--- libs/libmythtv/avformatdecoder.h    (revision 11213)
285+++ libs/libmythtv/avformatdecoder.h    (working copy)
286@@ -184,6 +184,7 @@
287     void SeekReset(long long, uint skipFrames, bool doFlush, bool discardFrames);
288 
289     bool SetupAudioStream(void);
290+    bool FixAudioStreamSubIndexes(bool wasDual, bool isDual);
291 
292     /// Update our position map, keyframe distance, and the like.
293     /// Called for key frame packets.
294Index: libs/libmythtv/mpegrecorder.cpp
295===================================================================
296--- libs/libmythtv/mpegrecorder.cpp     (revision 11213)
297+++ libs/libmythtv/mpegrecorder.cpp     (working copy)
298@@ -65,6 +65,11 @@
299     "SVCD",      "DVD-Special 1", "DVD-Special 2", 0
300 };
301 
302+const char* MpegRecorder::languages[] =
303+{
304+    "Language I", "Language II", "Dual", 0
305+};
306+
307 const char* MpegRecorder::aspectRatio[] =
308 {
309     "Square", "4:3", "16:9", "2.21:1", 0
310@@ -90,7 +95,7 @@
311     streamtype(0),            aspectratio(2),
312     audtype(2),               audsamplerate(48000),
313     audbitratel1(14),         audbitratel2(14),
314-    audvolume(80),
315+    audvolume(80),            language(0),
316     // Input file descriptors
317     chanfd(-1),               readfd(-1),
318     // Keyframe tracking inforamtion
319@@ -201,6 +206,22 @@
320                     QString("%1 is invalid").arg(value));
321         }
322     }
323+    else if (opt == "mpeg2language")
324+    {
325+        bool found = false;
326+        for (unsigned int i = 0; i < sizeof(languages) / sizeof(char*); i++)
327+        {
328+            if (QString(languages[i]) == value)
329+            {
330+                language = i;
331+                found = true;
332+                break;
333+            }
334+        }
335+
336+        if (!found)
337+            cerr << "MPEG2 language (stereo) flag : " << value << " is invalid\n";
338+    }
339     else if (opt == "mpeg2aspectratio")
340     {
341         bool found = false;
342@@ -268,6 +289,8 @@
343               profile->byName("mpeg2streamtype")->getValue());
344     SetOption("mpeg2aspectratio",
345               profile->byName("mpeg2aspectratio")->getValue());
346+    SetOption("mpeg2language",
347+              profile->byName("mpeg2language")->getValue());
348 
349     SetIntOption(profile, "samplerate");
350     SetOption("mpeg2audtype", profile->byName("mpeg2audtype")->getValue());
351@@ -322,6 +345,45 @@
352         return false;
353     }
354 
355+    struct v4l2_tuner vt;
356+    memset(&vt, 0, sizeof(struct v4l2_tuner));
357+    if (ioctl(chanfd, VIDIOC_G_TUNER, &vt) < 0)
358+    {
359+        cerr << "Error getting tuner settings\n";
360+        perror("VIDIOC_G_TUNER:");
361+        return false;
362+    }
363+
364+    switch(language)
365+    {
366+        case 0:
367+        default: /* just in case */
368+            vt.audmode=V4L2_TUNER_MODE_LANG1;
369+            break;
370+
371+        case 1:
372+            vt.audmode=V4L2_TUNER_MODE_LANG2;
373+            break;
374+
375+        case 2:
376+            if(audtype != 1)
377+                vt.audmode=V4L2_TUNER_MODE_STEREO;
378+            else
379+            {
380+                vt.audmode=V4L2_TUNER_MODE_LANG1;
381+                cerr << "Dual audio mode incompatible with Layer I audio, falling back to Language I (mpeg2language)\n";
382+            }
383+            break;
384+    }
385+
386+    if (ioctl(chanfd, VIDIOC_S_TUNER, &vt) < 0)
387+    {
388+        cerr << "Error setting tuner audio mode\n";
389+        perror("VIDIOC_S_TUNER:");
390+        return false;
391+    }
392+
393+
394     struct v4l2_control ctrl;
395     ctrl.id = V4L2_CID_AUDIO_VOLUME;
396     ctrl.value = 65536 / 100 *audvolume;
397Index: libs/libmythtv/recordingprofile.cpp
398===================================================================
399--- libs/libmythtv/recordingprofile.cpp (revision 11213)
400+++ libs/libmythtv/recordingprofile.cpp (working copy)
401@@ -214,6 +214,26 @@
402     };
403 };
404 
405+class MPEG2language: public CodecParam, public ComboBoxSetting {
406+    public:
407+        MPEG2language(const RecordingProfile& parent):
408+            CodecParam(parent, "mpeg2language") {
409+            setLabel(QObject::tr("SAP/Bilingual"));
410+
411+            addSelection("Language I");
412+            addSelection("Language II");
413+            addSelection("Dual");
414+            setValue(0);
415+            setHelpText(QObject::tr("Chooses the language(s) to record when "
416+                                    "two languages are broadcast. Only Layer II "
417+                                    "supports the recording of two languages (Dual). "
418+                                    "Version 0.1.10+ of ivtv driver is required for this "
419+                                    "setting to have any effect."));
420+        };
421+};
422+
423+
424+
425 class AudioCompressionSettings: public VerticalConfigurationGroup,
426                                 public TriggeredConfigurationGroup {
427 public:
428@@ -243,6 +263,7 @@
429         params->setLabel("MPEG-2 Hardware Encoder");
430         params->addChild(new SampleRate(parent, false));
431         params->addChild(new MPEG2AudioBitrateSettings(parent));
432+        params->addChild(new MPEG2language(parent));
433         params->addChild(new MPEG2audVolume(parent));
434         addTarget("MPEG-2 Hardware Encoder", params);
435 
436Index: libs/libavcodec/mpegaudiodec.c
437===================================================================
438--- libs/libavcodec/mpegaudiodec.c      (revision 11213)
439+++ libs/libavcodec/mpegaudiodec.c      (working copy)
440@@ -1269,6 +1269,7 @@
441 
442     avctx->sample_rate = s->sample_rate;
443     avctx->channels = s->nb_channels;
444+    avctx->avcodec_dual_language = s->mode == MPA_DUAL ? 1 : 0;
445     avctx->bit_rate = s->bit_rate;
446     avctx->sub_id = s->layer;
447     return s->frame_size;
448Index: libs/libavcodec/avcodec.h
449===================================================================
450--- libs/libavcodec/avcodec.h   (revision 11213)
451+++ libs/libavcodec/avcodec.h   (working copy)
452@@ -823,6 +823,20 @@
453      */
454     int delay;
455 
456+
457+   /**
458+    * set when bilingual audio data has been detected.
459+    * 0 normally, 1 if dual language flag is set
460+    *
461+    * this is a hack to keep binary compatibility with
462+    * old versions of the library.
463+    *
464+    * - encoding: unused (called delay in this case...)
465+    * - decoding: set by lavc
466+    */
467+#define avcodec_dual_language delay
468+
469+
470     /* - encoding parameters */
471     float qcompress;  ///< amount of qscale change between easy & hard scenes (0.0-1.0)
472     float qblur;      ///< amount of qscale smoothing over time (0.0-1.0)