1 /*
2     SPDX-FileCopyrightText: 2003-2004 Christian Kvasny <chris@k3b.org>
3     SPDX-FileCopyrightText: 2008 Sebastian Trueg <trueg@k3b.org>
4     SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl>
5     SPDX-FileCopyrightText: 1998-2010 Sebastian Trueg <trueg@k3b.org>
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #include "k3bvcdtrack.h"
11 #include "k3bglobals.h"
12 #include "k3b_i18n.h"
13 
14 #include <KConfig>
15 
16 #include <QDebug>
17 #include <QString>
18 #include <QFileInfo>
19 
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 
VcdTrack(QList<K3b::VcdTrack * > * parent,const QString & filename)25 K3b::VcdTrack::VcdTrack( QList<K3b::VcdTrack*>* parent, const QString& filename )
26         : mpeg_info(Q_NULLPTR),
27         m_pbcnumkeys( true ),
28         m_pbcnumkeysuserdefined( false ),
29         m_file( filename )
30 {
31     m_parent = parent;
32     m_title = QFileInfo( m_file ).completeBaseName();
33 
34     Q_FOREACH( PbcTracks playback, trackPlaybackValues() ) {
35         m_pbctrackmap.insert( playback, 0L );
36         m_pbcnontrackmap.insert( playback, DISABLED );
37         m_pbcusrdefmap.insert( playback, false );
38     }
39 
40     m_reactivity = false;
41 
42     m_definedkeysmap.clear();
43 
44     mpeg_info = new Mpeginfo();
45 }
46 
47 
~VcdTrack()48 K3b::VcdTrack::~VcdTrack()
49 {
50     if (mpeg_info) {
51         delete mpeg_info;
52         mpeg_info = Q_NULLPTR;
53     }
54 }
55 
56 
size() const57 KIO::filesize_t K3b::VcdTrack::size() const
58 {
59     return m_file.size();
60 }
61 
index() const62 int K3b::VcdTrack::index() const
63 {
64     // (trueg): I have no idea why I need to const cast here!
65     int i = m_parent->indexOf( const_cast<K3b::VcdTrack*>( this ) );
66     if ( i < 0 )
67         qDebug() << "(K3b::VcdTrack) I'm not part of my parent!";
68     return i;
69 }
70 
71 
trackPlaybackValues()72 QList<K3b::VcdTrack::PbcTracks> K3b::VcdTrack::trackPlaybackValues()
73 {
74     QList<PbcTracks> playbacks;
75     playbacks << PREVIOUS << NEXT << RETURN << DEFAULT << AFTERTIMEOUT;
76     return playbacks;
77 }
78 
79 
addToRevRefList(K3b::VcdTrack * revreftrack)80 void K3b::VcdTrack::addToRevRefList( K3b::VcdTrack* revreftrack )
81 {
82     qDebug() << "K3b::VcdTrack::addToRevRefList: track = " << revreftrack;
83 
84     m_revreflist.append( revreftrack );
85 
86     qDebug() << "K3b::VcdTrack::hasRevRef count = " << m_revreflist.count() << " empty = " << m_revreflist.isEmpty();
87 }
88 
delFromRevRefList(K3b::VcdTrack * revreftrack)89 void K3b::VcdTrack::delFromRevRefList( K3b::VcdTrack* revreftrack )
90 {
91     m_revreflist.removeAll( revreftrack );
92 }
93 
hasRevRef()94 bool K3b::VcdTrack::hasRevRef()
95 {
96     return !m_revreflist.isEmpty() ;
97 }
98 
delRefToUs()99 void K3b::VcdTrack::delRefToUs()
100 {
101     Q_FOREACH( K3b::VcdTrack* track, m_revreflist ) {
102         Q_FOREACH( PbcTracks playback, trackPlaybackValues() ) {
103             qDebug() << "K3b::VcdTrack::delRefToUs count = " << m_revreflist.count() << " empty = " << m_revreflist.isEmpty() << " track = " << track << " this = " << this;
104             if( this == track->getPbcTrack( playback ) ) {
105                 track->setPbcTrack( playback );
106                 track->setUserDefined( playback, false );
107                 track->delFromRevRefList( this );
108             }
109         }
110     }
111 }
112 
delRefFromUs()113 void K3b::VcdTrack::delRefFromUs()
114 {
115     Q_FOREACH( PbcTracks playback, trackPlaybackValues() ) {
116         if ( this->getPbcTrack( playback ) ) {
117             this->getPbcTrack( playback ) ->delFromRevRefList( this );
118         }
119     }
120 }
121 
setPbcTrack(PbcTracks which,K3b::VcdTrack * pbctrack)122 void K3b::VcdTrack::setPbcTrack( PbcTracks which, K3b::VcdTrack* pbctrack )
123 {
124     qDebug() << "K3b::VcdTrack::setPbcTrack " << which << ", " << pbctrack;
125     m_pbctrackmap[which] = pbctrack;
126 }
127 
setPbcNonTrack(PbcTracks which,PbcTypes type)128 void K3b::VcdTrack::setPbcNonTrack( PbcTracks which, PbcTypes type )
129 {
130     qDebug() << "K3b::VcdTrack::setNonPbcTrack " << which << ", " << type;
131     m_pbcnontrackmap[which] = type;
132 }
133 
setUserDefined(PbcTracks which,bool ud)134 void K3b::VcdTrack::setUserDefined( PbcTracks which, bool ud )
135 {
136     m_pbcusrdefmap[which] = ud;
137 }
138 
getPbcTrack(PbcTracks which)139 K3b::VcdTrack* K3b::VcdTrack::getPbcTrack( PbcTracks which )
140 {
141     if ( m_pbctrackmap.find( which ) == m_pbctrackmap.end() )
142         return 0;
143     else
144         return m_pbctrackmap[ which ];
145 }
146 
getNonPbcTrack(PbcTracks which)147 int K3b::VcdTrack::getNonPbcTrack( PbcTracks which )
148 {
149     if ( m_pbcnontrackmap.find( which ) == m_pbcnontrackmap.end() )
150         return 0;
151     else
152         return m_pbcnontrackmap[ which ];
153 }
154 
isPbcUserDefined(PbcTracks which)155 bool K3b::VcdTrack::isPbcUserDefined( PbcTracks which )
156 {
157     return m_pbcusrdefmap[ which ];
158 }
159 
resolution()160 QString K3b::VcdTrack::resolution()
161 {
162     if ( mpeg_info->has_video ) {
163         for ( int i = 0; i < 2; i++ ) {
164             if ( mpeg_info->video[ i ].seen ) {
165                 return QString( "%1 x %2" ).arg( mpeg_info->video[ i ].hsize ).arg( mpeg_info->video[ i ].vsize );
166             }
167         }
168     }
169 
170     return i18n( "n/a" );
171 }
172 
highresolution()173 QString K3b::VcdTrack::highresolution()
174 {
175     if ( mpeg_info->has_video ) {
176         if ( mpeg_info->video[ 2 ].seen ) {
177             return QString( "%1 x %2" ).arg( mpeg_info->video[ 2 ].hsize ).arg( mpeg_info->video[ 2 ].vsize );
178         }
179     }
180     return i18n( "n/a" );
181 }
182 
video_frate()183 QString K3b::VcdTrack::video_frate()
184 {
185     if ( mpeg_info->has_video ) {
186         for ( int i = 0; i < 2; i++ ) {
187             if ( mpeg_info->video[ i ].seen ) {
188                 return QString::number( mpeg_info->video[ i ].frate );
189             }
190         }
191     }
192 
193     return i18n( "n/a" );
194 }
195 
video_bitrate()196 QString K3b::VcdTrack::video_bitrate()
197 {
198     if ( mpeg_info->has_video ) {
199         for ( int i = 0; i < 2; i++ ) {
200             if ( mpeg_info->video[ i ].seen ) {
201                 return i18np( "1 bit/s", "%1 bits/s" , mpeg_info->video[ i ].bitrate ) ;
202             }
203         }
204     }
205 
206     return i18n( "n/a" );
207 }
208 
209 
210 
video_format()211 QString K3b::VcdTrack::video_format()
212 {
213     if ( mpeg_info->has_video ) {
214         for ( int i = 0; i < 2; i++ ) {
215             if ( mpeg_info->video[ i ].seen ) {
216                 switch ( mpeg_info->video[ i ].video_format ) {
217                     case 0 :
218                         return i18n( "Component" );
219                         break;
220                     case 1 :
221                         return "PAL";
222                         break;
223                     case 2 :
224                         return "NTSC";
225                         break;
226                     case 3 :
227                         return "SECAM";
228                         break;
229                     case 4 :
230                         return "MAC";
231                         break;
232                     case 5 :
233                     default:
234                         return i18n( "Unspecified" );
235                         qDebug() << "K3b::VcdTrack::video_format() :" << mpeg_info->video[ i ].video_format;
236                         break;
237                 }
238             }
239         }
240     }
241     return i18n( "n/a" );
242 }
243 
video_chroma()244 QString K3b::VcdTrack::video_chroma()
245 {
246     if ( mpeg_info->has_video ) {
247         // MPEG1 only supports 4:2:0 Format
248         if ( version() == K3b::MpegInfo::MPEG_VERS_MPEG1 )
249             return QString( "4:2:0" );
250 
251         for ( int i = 0; i < 2; i++ ) {
252             if ( mpeg_info->video[ i ].seen ) {
253                 switch ( mpeg_info->video[ i ].chroma_format ) {
254                     case 1 :
255                         return QString( "4:2:0" );
256                         break;
257                     case 2 :
258                         return QString( "4:2:2" );
259                         break;
260                     case 3 :
261                         return QString( "4:4:4" );
262                         break;
263 
264                 }
265             }
266         }
267     }
268 
269     return i18n( "n/a" );
270 }
271 
audio_layer()272 QString K3b::VcdTrack::audio_layer()
273 {
274     if ( mpeg_info->has_audio ) {
275         for ( int i = 0; i < 2; i++ ) {
276             if ( mpeg_info->audio[ i ].seen ) {
277                 return QString::number( mpeg_info->audio[ i ].layer );
278             }
279         }
280     }
281 
282     return i18n( "n/a" );
283 }
284 
audio_bitrate()285 QString K3b::VcdTrack::audio_bitrate()
286 {
287     if ( mpeg_info->has_audio ) {
288         for ( int i = 0; i < 2; i++ ) {
289             if ( mpeg_info->audio[ i ].seen ) {
290                 return i18np( "1 bit/s", "%1 bits/s" , mpeg_info->audio[ i ].bitrate ) ;
291             }
292         }
293     }
294 
295     return i18n( "n/a" );
296 }
297 
audio_sampfreq()298 QString K3b::VcdTrack::audio_sampfreq()
299 {
300     if ( mpeg_info->has_audio ) {
301         for ( int i = 0; i < 2; i++ ) {
302             if ( mpeg_info->audio[ i ].seen ) {
303                 return i18n( "%1 Hz" , mpeg_info->audio[ i ].sampfreq ) ;
304             }
305         }
306     }
307 
308     return i18n( "n/a" );
309 }
310 
audio_mode()311 QString K3b::VcdTrack::audio_mode( )
312 {
313     if ( mpeg_info->has_audio ) {
314         for ( int i = 2; i >= 0; i-- )
315             if ( mpeg_info->audio[ i ].seen )
316                 return QString( audio_type2str( mpeg_info->audio[ i ].version, mpeg_info->audio[ i ].mode, i ) );
317 
318     }
319 
320     return i18n( "n/a" );
321 }
322 
audio_copyright()323 QString K3b::VcdTrack::audio_copyright( )
324 {
325     if ( mpeg_info->has_audio ) {
326         for ( int i = 2; i >= 0; i-- ) {
327             if ( mpeg_info->audio[ i ].seen )
328             {
329                 if ( mpeg_info->audio[ i ].copyright )
330                     return QString( "(c) " ) + ( mpeg_info->audio[ i ].original ? i18n( "original" ) : i18n( "duplicate" ) );
331                 else
332                     return ( mpeg_info->audio[ i ].original ? i18n( "original" ) : i18n( "duplicate" ) );
333             }
334         }
335     }
336 
337     return i18n( "n/a" );
338 }
339 
mpegTypeS(bool audio)340 QString K3b::VcdTrack::mpegTypeS( bool audio )
341 {
342     if ( mpeg_info->has_video && !audio ) {
343         for ( int i = 0; i < 3; i++ )
344             if ( mpeg_info->video[ i ].seen ) {
345                 if ( i == 0 ) {
346                     return QString( "MPEG%1 ").arg(mpeg_info->version ) + i18n( "Motion Picture" );
347                 } else {
348                     return QString( "MPEG%1 ").arg(mpeg_info->version ) + i18n( "Still Picture" );
349                 }
350             }
351     }
352     if ( mpeg_info->has_audio && audio ) {
353         for ( int i = 0; i < 3; i++ )
354             if ( mpeg_info->audio[ i ].seen ) {
355                 return QString( "MPEG%1 ").arg(mpeg_info->audio[ i ].version ) + i18n( "Layer %1" , mpeg_info->audio[ i ].layer );
356             }
357     }
358 
359     return i18n( "n/a" );
360 }
361 
mpegType()362 int K3b::VcdTrack::mpegType( )
363 {
364     if ( mpeg_info->has_video ) {
365         for ( int i = 0; i < 3; i++ )
366             if ( mpeg_info->video[ i ].seen ) {
367                 if ( i == 0 ) {
368                     return 0; // MPEG_MOTION;
369                 } else {
370                     return 1; // MPEG_STILL;
371                 }
372             }
373     }
374     if ( mpeg_info->has_audio ) {
375         for ( int i = 0; i < 3; i++ )
376             if ( mpeg_info->audio[ i ].seen )
377                 return 2; // MPEG_AUDIO;
378     }
379 
380     return -1; // MPEG_UNKNOWN;
381 }
382 
audio_type2str(unsigned int version,unsigned int audio_mode,unsigned int audio_type)383 QString K3b::VcdTrack::audio_type2str( unsigned int version, unsigned int audio_mode, unsigned int audio_type )
384 {
385     qDebug() << "K3b::VcdTrack::audio_type2str() version:" << version << " audio_mode:" << audio_mode << " audio_type:" << audio_type;
386 
387     QString audio_types[ 3 ][ 5 ] = {
388                                         {
389                                             i18n( "unknown" ),
390                                             i18n( "invalid" ),
391                                             QString(),
392                                             QString(),
393                                             QString()
394                                         },
395                                         {
396                                             i18n( "stereo" ),
397                                             i18n( "joint stereo" ),
398                                             i18n( "dual channel" ),
399                                             i18n( "single channel" )
400                                         },
401                                         {
402                                             QString(),
403                                             i18n( "dual channel" ),
404                                             i18n( "surround sound" ),
405                                             QString(),
406                                             QString()
407                                         }
408                                     };
409     switch ( version ) {
410         case K3b::MpegInfo::MPEG_VERS_MPEG1:
411             return audio_types[ 1 ][ audio_mode ];
412             break;
413 
414         case K3b::MpegInfo::MPEG_VERS_MPEG2:
415             if ( audio_type > 0 ) {
416                 return audio_types[ 2 ][ audio_type ];
417             }
418             return audio_types[ 1 ][ audio_mode ];
419             break;
420     }
421 
422     return i18n( "n/a" );
423 }
424 
425 // convert a time in second to HH:mm:ss notation
SecsToHMS(double duration)426 QString K3b::VcdTrack::SecsToHMS( double duration )
427 {
428     byte hours = ( byte ) ( duration / 3600 );
429     byte mins = ( byte ) ( ( duration / 60 ) - ( hours * 60 ) );
430     float secs = duration - 60 * mins - 3600 * hours;
431     if ( hours != 0 ) {
432         return QString( "%1:" ).arg( hours ).rightJustified( 3, ' ' ) + QString( "%1:" ).arg( mins ).rightJustified( 3, '0' ) + QString::number( secs, 'f', 2 );
433     }
434     if ( mins != 0 ) {
435         return QString( "%1:" ).arg( mins ).rightJustified( 3, '0' ) + QString::number( secs, 'f', 2 );
436     }
437     return QString::number( secs, 'f', 2 );
438 }
439 
PrintInfo()440 void K3b::VcdTrack::PrintInfo()
441 {
442 
443     qDebug() << "K3b::VcdTrack::PrintInfo() .....................";
444     qDebug() << "  version          : MPEG" << version();
445     qDebug() << "  duration         : " << duration();
446     qDebug() << "  muxrate          : " << muxrate();
447     qDebug() << "  video ......................................";
448     qDebug() << "    type           : " << mpegTypeS();
449     qDebug() << "    resolution     : " << resolution();
450     qDebug() << "    high resolution: " << highresolution();
451     qDebug() << "    frate          : " << video_frate();
452     qDebug() << "    bitrate        : " << video_bitrate();
453     qDebug() << "    format         : " << video_format( );
454     qDebug() << "    chroma         : " << video_chroma( );
455     qDebug() << "  audio ......................................";
456     qDebug() << "    type           : " << mpegTypeS( true );
457     qDebug() << "    mode           : " << audio_mode();
458     qDebug() << "    layer          : " << audio_layer();
459     qDebug() << "    bitrate        : " << audio_bitrate();
460     qDebug() << "    sampfreq       : " << audio_sampfreq();
461 
462 }
463