diff options
Diffstat (limited to 'libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp')
-rw-r--r-- | libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp | 844 |
1 files changed, 844 insertions, 0 deletions
diff --git a/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp b/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp new file mode 100644 index 0000000..583a0aa --- /dev/null +++ b/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp @@ -0,0 +1,844 @@ +/* +* +* $Id: k3bmpeginfo.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +// kde includes +#include <klocale.h> + +// k3b includes +#include "k3bmpeginfo.h" + +static const double frame_rates[ 16 ] = + { + 0.0, 24000.0 / 1001, 24.0, 25.0, + 30000.0 / 1001, 30.0, 50.0, 60000.0 / 1001, + 60.0, 0.0, + }; + +K3bMpegInfo::K3bMpegInfo( const char* filename ) + : m_mpegfile( 0 ), + m_filename( filename ), + m_done( false ), + m_buffstart( 0 ), + m_buffend( 0 ), + m_buffer( 0 ), + m_initial_TS( 0.0 ) +{ + + mpeg_info = new Mpeginfo(); + + m_mpegfile = fopen( filename, "rb" ); + + if ( m_mpegfile == 0 ) { + kdDebug() << QString( "Unable to open %1" ).arg( m_filename ) << endl; + return ; + } + + if ( fseeko( m_mpegfile, 0, SEEK_END ) ) { + kdDebug() << QString( "Unable to seek in file %1" ).arg( m_filename ) << endl; + return ; + } + + llong lof = ftello( m_mpegfile ); + + if ( lof == -1 ) { + kdDebug() << QString( "Seeking to end of input file %1 failed." ).arg( m_filename ) << endl; + //give up.. + return ; + } else + m_filesize = lof; + + // nothing to do on an empty file + if ( !m_filesize ) { + kdDebug() << QString( "File %1 is empty." ).arg( m_filename ) << endl; + m_error_string = i18n( "File %1 is empty." ).arg( m_filename ); + return ; + } + + m_buffer = new byte[ BUFFERSIZE ]; + + MpegParsePacket ( ); + +} + +K3bMpegInfo::~K3bMpegInfo() +{ + if ( m_buffer ) { + delete[] m_buffer; + } + if ( m_mpegfile ) { + fclose( m_mpegfile ); + } + + delete mpeg_info; +} +bool K3bMpegInfo::MpegParsePacket () +{ + + /* verify the packet begins with a pack header */ + if ( !EnsureMPEG( 0, MPEG_PACK_HEADER_CODE ) ) { + llong code = GetNBytes( 0, 4 ); + + kdDebug() << QString( "(K3bMpegInfo::mpeg_parse_packet ()) pack header code 0x%1 expected, but 0x%2 found" ).arg( 0x00000100 + MPEG_PACK_HEADER_CODE, 0, 16 ).arg( code, 0, 16 ) << endl; + + if ( code == 0x00000100 + MPEG_SEQUENCE_CODE ) { + kdDebug() << "...this looks like a elementary video stream but a multiplexed program stream was required." << endl; + m_error_string = i18n( "This looks like a elementary video stream but a multiplexed program stream was required." ); + } + + if ( ( 0xfff00000 & code ) == 0xfff00000 ) { + kdDebug() << "...this looks like a elementary audio stream but a multiplexed program stream was required." << endl; + m_error_string = i18n( "This looks like a elementary audio stream but a multiplexed program stream was required." ); + } + + if ( code == 0x52494646 ) { + kdDebug() << "...this looks like a RIFF header but a plain multiplexed program stream was required." << endl; + m_error_string = i18n( "This looks like a RIFF header but a plain multiplexed program stream was required." ); + } + + return false; + } + + + /* take a look at the pack header */ + int offset = 0; + while ( GetByte( offset ) == 0x00 ) + offset ++; + //here we're on the first non null byte let's get back to leave two zeros (packet start code) + offset -= 2; + + if ( offset != 0 ) { + // we actually skipped some zeroes + kdDebug() << QString( "Skipped %1 zeroes at start of file" ).arg( offset ) << endl; + } + + // here while schleife + while ( offset != -1 ) { + offset = MpegParsePacket( offset ); + } + + /* + int pkt = 0; + offset = FindNextMarker( 0, MPEG_PACK_HEADER_CODE ); + + while ( offset != -1 ) { + pkt++; + offset = FindNextMarker( offset+1, MPEG_PACK_HEADER_CODE ); + } + + kdDebug() << "Pkt found: " << pkt << endl; + */ + + //seek the file duration by fetching the last PACK + //and reading its timestamp + llong last_pack = bdFindNextMarker( m_filesize - 13, MPEG_PACK_HEADER_CODE ); + // -12 because a PACK is at least 12 bytes + double duration; + last_pack += 4; + int bits = GetByte( last_pack ) >> 4; + + if ( bits == 0x2 ) /* %0010 ISO11172-1 */ + { + duration = ReadTS( last_pack ); + } else if ( bits >> 2 == 0x1 ) /* %01xx ISO13818-1 */ + { + duration = ReadTSMpeg2( last_pack ); + } else { + kdDebug() << QString( "no timestamp found" ) << endl; + duration = ReadTS( last_pack ); + } + + mpeg_info->playing_time = duration - m_initial_TS; + + + if ( !mpeg_info->has_video ) + for ( int i = 0; i < 2; i++ ) + if ( mpeg_info->video[ i ].seen ) + mpeg_info->has_video = true; + + if ( !mpeg_info->has_audio ) + for ( int i = 0; i < 2; i++ ) + if ( mpeg_info->audio[ i ].seen ) + mpeg_info->has_audio = true; + + return true; +} + +llong K3bMpegInfo::MpegParsePacket ( llong offset ) +{ + byte mark = 0; + uint size = 0; + + /* continue until start code seen */ + offset = FindNextMarker( offset, &mark ); + + if ( offset < 0 ) + return offset; + + switch ( mark ) { + int bits; + + case MPEG_PACK_HEADER_CODE: + // kdDebug() << QString( "MPEG_PACK_HEADER_CODE @ %1" ).arg( offset ) << endl; + + offset += 4; + + if ( mpeg_info->version != MPEG_VERS_INVALID ) + break; + + bits = GetByte( offset ) >> 4; + + if ( bits == 0x2 ) /* %0010 ISO11172-1 */ + { + mpeg_info->version = MPEG_VERS_MPEG1; + + unsigned long muxrate = 0; + + muxrate = ( GetByte( offset + 5 ) & 0x7F ) << 15; + muxrate |= ( GetByte( offset + 6 ) << 7 ); + muxrate |= ( GetByte( offset + 7 ) >> 1 ); + + mpeg_info->muxrate = muxrate * 50 * 8; + + if ( m_initial_TS == 0.0 ) + { + m_initial_TS = ReadTS( offset ); + kdDebug() << QString( "Initial TS = %1" ).arg( m_initial_TS ) << endl; + } + + } else if ( bits >> 2 == 0x1 ) /* %01xx ISO13818-1 */ + { + mpeg_info->version = MPEG_VERS_MPEG2; + + unsigned long muxrate = 0; + muxrate = GetByte( offset + 6 ) << 14; + muxrate |= GetByte( offset + 7 ) << 6; + muxrate |= GetByte( offset + 8 ) >> 2; + + mpeg_info->muxrate = muxrate * 50 * 8; + + if ( m_initial_TS == 0.0 ) + { + m_initial_TS = ReadTSMpeg2( offset ); + kdDebug() << QString( "Initial TS = %1" ).arg( m_initial_TS ) << endl; + } + + } else { + kdDebug() << QString( "packet not recognized as either version 1 or 2 (%1)" ).arg( bits ) << endl; + mpeg_info->version = MPEG_VERS_INVALID; + return -1; + } + break; + + case MPEG_SYSTEM_HEADER_CODE: + case MPEG_PAD_CODE: + case MPEG_PRIVATE_1_CODE: + case MPEG_VIDEO_E0_CODE: + case MPEG_VIDEO_E1_CODE: + case MPEG_VIDEO_E2_CODE: + case MPEG_AUDIO_C0_CODE: + case MPEG_AUDIO_C1_CODE: + case MPEG_AUDIO_C2_CODE: + + offset += 4; + size = GetSize( offset ); + offset += 2; + // kdDebug() << QString( "offset = %1, size = %2" ).arg( offset ).arg( size ) << endl; + + switch ( mark ) { + case MPEG_SYSTEM_HEADER_CODE: + // kdDebug() << QString( "Systemheader: %1" ).arg( m_code, 0, 16 ) << endl; + break; + + case MPEG_VIDEO_E0_CODE: + case MPEG_VIDEO_E1_CODE: + case MPEG_VIDEO_E2_CODE: + ParseVideo( offset, mark ); + // _analyze_video_pes (code & 0xff, buf + pos, size, !parse_pes, ctx); + if ( mpeg_info->has_video && mpeg_info->has_audio ) { + return -1; + } else if ( mark == MPEG_VIDEO_E0_CODE || mpeg_info->version == MPEG_VERS_MPEG2 && mark == MPEG_VIDEO_E1_CODE || mpeg_info->version == MPEG_VERS_MPEG1 && mark == MPEG_VIDEO_E2_CODE ) { + mpeg_info->has_video = true; + offset = FindNextAudio( offset ); + } + break; + case MPEG_AUDIO_C0_CODE: + case MPEG_AUDIO_C1_CODE: + case MPEG_AUDIO_C2_CODE: + offset = SkipPacketHeader( offset - 6 ); + ParseAudio( offset, mark ); + // audio packet doesn't begin with 0xFFF + if ( !mpeg_info->audio[ GetAudioIdx( mark ) ].seen ) { + int a_idx = GetAudioIdx( mark ); + while ( ( offset < m_filesize - 10 ) && !mpeg_info->audio[ a_idx ].seen ) { + if ( ( GetByte( offset ) == 0xFF ) && ( GetByte( offset + 1 ) & 0xF0 ) == 0xF0 ) + ParseAudio( offset, mark ); + offset++; + } + } + + mpeg_info->has_audio = true; + if ( mpeg_info->has_video ) + return -1; + + offset = FindNextVideo( offset ); + break; + + case MPEG_PRIVATE_1_CODE: + kdDebug() << QString( "PrivateCode: %1" ).arg( mark, 0, 16 ) << endl; + break; + } + break; + + case MPEG_PROGRAM_END_CODE: + kdDebug() << QString( "ProgramEndCode: %1" ).arg( mark, 0, 16 ) << endl; + offset += 4; + break; + + case MPEG_PICTURE_CODE: + kdDebug() << QString( "PictureCode: %1" ).arg( mark, 0, 16 ) << endl; + offset += 3; + break; + + default: + offset += 4; + break; + } + + return offset; +} + +byte K3bMpegInfo::GetByte( llong offset ) +{ + unsigned long nread; + if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) { + + if ( fseeko( m_mpegfile, offset, SEEK_SET ) ) { + kdDebug() << QString( "could not get seek to offset (%1) in file %2 (size:%3)" ).arg( offset ).arg( m_filename ).arg( m_filesize ) << endl; + return 0x11; + } + nread = fread( m_buffer, 1, BUFFERSIZE, m_mpegfile ); + m_buffstart = offset; + m_buffend = offset + nread; + if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) { + // weird + kdDebug() << QString( "could not get offset %1 in file %2 [%3]" ).arg( offset ).arg( m_filename ).arg( m_filesize ) << endl; + return 0x11; + } + } + return m_buffer[ offset - m_buffstart ]; +} + +// same as above but improved for backward search +byte K3bMpegInfo::bdGetByte( llong offset ) +{ + unsigned long nread; + if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) { + llong start = offset - BUFFERSIZE + 1 ; + start = start >= 0 ? start : 0; + + fseeko( m_mpegfile, start, SEEK_SET ); + + nread = fread( m_buffer, 1, BUFFERSIZE, m_mpegfile ); + m_buffstart = start; + m_buffend = start + nread; + if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) { + // weird + kdDebug() << QString( "could not get offset %1 in file %2 [%3]" ).arg( offset ).arg( m_filename ).arg( m_filesize ) << endl; + + return 0x11; + } + } + return m_buffer[ offset - m_buffstart ]; +} + + +llong K3bMpegInfo::GetNBytes( llong offset, int n ) +{ + llong nbytes = 0; + n--; + for ( int i = 0; i < n; i++ ) + ( ( char* ) & nbytes ) [ n - i ] = GetByte( offset + i ); + + return nbytes; + +} + +// get a two byte size +unsigned short int K3bMpegInfo::GetSize( llong offset ) +{ + return GetByte( offset ) * 256 + GetByte( offset + 1 ); + // return GetNBytes( offset, 2 ); + +} + +bool K3bMpegInfo::EnsureMPEG( llong offset, byte mark ) +{ + if ( ( GetByte( offset ) == 0x00 ) && + ( GetByte( offset + 1 ) == 0x00 ) && + ( GetByte( offset + 2 ) == 0x01 ) && + ( GetByte( offset + 3 ) == mark ) ) + return true; + else + return false; +} + + +// find next 0x 00 00 01 xx sequence, returns offset or -1 on err +llong K3bMpegInfo::FindNextMarker( llong from ) +{ + llong offset; + for ( offset = from; offset < ( m_filesize - 4 ); offset++ ) { + if ( + ( GetByte( offset + 0 ) == 0x00 ) && + ( GetByte( offset + 1 ) == 0x00 ) && + ( GetByte( offset + 2 ) == 0x01 ) ) { + return offset; + } + } + return -1; +} + +// find next 0x 00 00 01 xx sequence, returns offset or -1 on err and +// change mark to xx +llong K3bMpegInfo::FindNextMarker( llong from, byte* mark ) +{ + llong offset = FindNextMarker( from ); + if ( offset >= 0 ) { + *mark = GetByte( offset + 3 ); + return offset; + } else { + return -1; + } +} + +// find next 0X00 00 01 mark +llong K3bMpegInfo::FindNextMarker( llong from, byte mark ) +{ + llong offset = from; + while ( offset >= 0 ) { + offset = FindNextMarker( offset ); + if ( offset < 0 ) { + return -1; + } + if ( EnsureMPEG( offset, mark ) ) { + return offset; + } else + offset++; + } + + //shouldn't be here + return -1; +} + +llong K3bMpegInfo::bdFindNextMarker( llong from, byte mark ) +{ + llong offset; + for ( offset = from; offset >= 0; offset-- ) { + if ( + ( bdGetByte( offset ) == 0x00 ) && + ( bdGetByte( offset + 1 ) == 0x00 ) && + ( bdGetByte( offset + 2 ) == 0x01 ) && + ( bdGetByte( offset + 3 ) == mark ) ) { + return offset; + } + } + return -1; +} + +llong K3bMpegInfo::bdFindNextMarker( llong from, byte* mark ) +{ + llong offset; + for ( offset = from; offset >= 0; offset-- ) { + if ( ( bdGetByte( offset ) == 0x00 ) && + ( bdGetByte( offset + 1 ) == 0x00 ) && + ( bdGetByte( offset + 2 ) == 0x01 ) ) { + *mark = bdGetByte( offset + 3 ); + return offset; + } + } + return -1; + +} + +llong K3bMpegInfo::FindNextVideo( llong from ) +{ + llong offset = from; + while ( offset >= 0 ) { + offset = FindNextMarker( offset ); + if ( offset < 0 ) { + return -1; + } + if ( EnsureMPEG( offset, MPEG_VIDEO_E0_CODE ) || EnsureMPEG( offset, MPEG_VIDEO_E1_CODE ) || EnsureMPEG( offset, MPEG_VIDEO_E2_CODE ) ) { + return offset; + } else + offset++; + } + + //shouldn't be here + return -1; +} + +llong K3bMpegInfo::FindNextAudio( llong from ) +{ + llong offset = from; + while ( offset >= 0 ) { + offset = FindNextMarker( offset ); + if ( offset < 0 ) { + return -1; + } + if ( EnsureMPEG( offset, MPEG_AUDIO_C0_CODE ) || EnsureMPEG( offset, MPEG_AUDIO_C1_CODE ) || EnsureMPEG( offset, MPEG_AUDIO_C2_CODE ) ) { + return offset; + } else + offset++; + } + + return -1; +} + + +int K3bMpegInfo::GetVideoIdx ( byte marker ) +{ + switch ( marker ) { + case MPEG_VIDEO_E0_CODE: + return 0; + break; + + case MPEG_VIDEO_E1_CODE: + return 1; + break; + + case MPEG_VIDEO_E2_CODE: + return 2; + break; + + default: + kdDebug() << "VideoCode not reached" << endl; + break; + } + + return -1; +} + +int K3bMpegInfo::GetAudioIdx ( byte marker ) +{ + switch ( marker ) { + case MPEG_AUDIO_C0_CODE: + return 0; + break; + + case MPEG_AUDIO_C1_CODE: + return 1; + break; + + case MPEG_AUDIO_C2_CODE: + return 2; + break; + + default: + kdDebug() << "VideoCode not reached" << endl; + break; + } + + return -1; +} + +llong K3bMpegInfo::SkipPacketHeader( llong offset ) +{ + byte tmp_byte; + if ( mpeg_info->version == MPEG_VERS_MPEG1 ) { + // skip startcode and packet size + offset += 6; + //remove stuffing bytes + tmp_byte = GetByte( offset ); + while ( tmp_byte & 0x80 ) + tmp_byte = GetByte( ++offset ); + + if ( ( tmp_byte & 0xC0 ) == 0x40 ) // next two bits are 01 + offset += 2; + + tmp_byte = GetByte( offset ); + if ( ( tmp_byte & 0xF0 ) == 0x20 ) + offset += 5; + else if ( ( tmp_byte & 0xF0 ) == 0x30 ) + offset += 10; + else + offset++; + + return offset; + } else if ( mpeg_info->version == MPEG_VERS_MPEG2 ) { + return ( offset + 9 + GetByte( offset + 8 ) ); + } else + return ( offset + 10 ); +} + +void K3bMpegInfo::ParseAudio ( llong offset, byte marker ) +{ + unsigned brate, srate; + bool mpeg2_5 = false; + + const int a_idx = GetAudioIdx( marker ); + + if ( mpeg_info->audio[ a_idx ].seen ) /* we have it already */ + return ; + + if ( ( GetByte( offset ) != 0xFF ) || ( ( GetByte( offset + 1 ) & 0xF0 ) != 0xF0 ) ) { + // doesn't start with 12 bits set + if ( ( GetByte( offset ) != 0xFF ) || ( ( GetByte( offset + 1 ) & 0xE0 ) != 0xE0 ) ) { + // doesn't start with 11 bits set + return ; + } else { + // start with 11 bits set + mpeg2_5 = true; + } + } + + // Find mpeg version 1.0 or 2.0 + if ( GetByte( offset + 1 ) & 0x08 ) { + if ( !mpeg2_5 ) + mpeg_info->audio[ a_idx ].version = 1; + else + return ; // invalid 01 encountered + } else { + if ( !mpeg2_5 ) + mpeg_info->audio[ a_idx ].version = 2; + else + mpeg_info->audio[ a_idx ].version = 3; //for mpeg 2.5 + } + + // Find Layer + mpeg_info->audio[ a_idx ].layer = ( GetByte( offset + 1 ) & 0x06 ) >> 1; + switch ( mpeg_info->audio[ a_idx ].layer ) { + case 0: + mpeg_info->audio[ a_idx ].layer = 0; + break; + case 1: + mpeg_info->audio[ a_idx ].layer = 3; + break; + case 2: + mpeg_info->audio[ a_idx ].layer = 2; + break; + case 3: + mpeg_info->audio[ a_idx ].layer = 1; + break; + } + + // Protection Bit + mpeg_info->audio[ a_idx ].protect = GetByte( offset + 1 ) & 0x01; + if ( mpeg_info->audio[ a_idx ].protect ) + mpeg_info->audio[ a_idx ].protect = 0; + else + mpeg_info->audio[ a_idx ].protect = 1; + + const unsigned bit_rates[ 4 ][ 16 ] = { + { + 0, + }, + {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}, + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0} + }; + + + /* const unsigned bit_rates [ 3 ][ 3 ][ 16 ] = { + { + {0, }, + {0, }, + {0, }, + }, + { + {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}, + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0} + }, + { + {0, 32, 48, 56, 64, 80 , 96 , 112, 128, 144, 160, 176, 192, 224, 256, 0}, + {0, 8, 16, 24, 32, 40, 48, 56, 64 , 80 , 96 , 112, 128, 144, 160, 0}, + {0, 8, 16, 24, 32, 40, 48, 56, 64 , 80 , 96 , 112, 128, 144, 160, 0} + } + }; + */ + + const unsigned sampling_rates[ 4 ][ 4 ] = { + { + 0, + }, + {44100, 48000, 32000, 0}, //mpeg 1 + {22050, 24000, 16000, 0}, //mpeg 2 + {11025, 12000, 8000, 0} //mpeg 2.5 + }; + + + // Bitrate index and sampling index to pass through the array + brate = GetByte( offset + 2 ) >> 4; + srate = ( GetByte( offset + 2 ) & 0x0f ) >> 2; + + mpeg_info->audio[ a_idx ].bitrate = 1024 * bit_rates[ mpeg_info->audio[ a_idx ].layer ][ brate ]; + mpeg_info->audio[ a_idx ].byterate = ( float ) ( mpeg_info->audio[ a_idx ].bitrate / 8.0 ); + mpeg_info->audio[ a_idx ].sampfreq = sampling_rates[ mpeg_info->audio[ a_idx ].version ][ srate ]; + + // Audio mode + mpeg_info->audio[ a_idx ].mode = 1 + ( GetByte( offset + 3 ) >> 6 ) ; + + // Copyright bit + if ( GetByte( offset + 3 ) & 0x08 ) + mpeg_info->audio[ a_idx ].copyright = true; + else + mpeg_info->audio[ a_idx ].copyright = false; + + // Original/Copy bit + if ( GetByte( offset + 3 ) & 0x04 ) + mpeg_info->audio[ a_idx ].original = true; + else + mpeg_info->audio[ a_idx ].original = false; + + + mpeg_info->audio[ a_idx ].seen = true; +} + +void K3bMpegInfo::ParseVideo ( llong offset, byte marker ) +{ + unsigned long aratio, frate, brate; + + const int v_idx = GetVideoIdx( marker ); + + const double aspect_ratios[ 16 ] = { + 0.0000, 1.0000, 0.6735, 0.7031, + 0.7615, 0.8055, 0.8437, 0.8935, + 0.9375, 0.9815, 1.0255, 1.0695, + 1.1250, 1.1575, 1.2015, 0.0000 + }; + + if ( mpeg_info->video[ v_idx ].seen ) /* we have it already */ + return ; + + offset = FindNextMarker( offset + 1, MPEG_SEQUENCE_CODE ); + + if ( !offset ) + return ; + + offset += 4; + + mpeg_info->video[ v_idx ].hsize = GetSize( offset ) >> 4; + mpeg_info->video[ v_idx ].vsize = GetSize( offset + 1 ) & 0x0FFF; + + // Get picture rate + offset += 3; // after picture sizes + + aratio = ( GetByte( offset ) & 0x0F ) >> 4; + mpeg_info->video[ v_idx ].aratio = aspect_ratios[ aratio ]; + + // offset += 3; // after picture sizes + frate = GetByte( offset ) & 0x0F; + mpeg_info->video[ v_idx ].frate = frame_rates[ frate ]; + + offset += 1; // after picture rate + + // 18 following bytes are the bitrate /400 + + //read first 16 bytes + brate = GetSize( offset ); + // scale + brate <<= 2; + byte lasttwo = GetByte( offset + 2 ); + lasttwo >>= 6; + brate |= lasttwo; + + mpeg_info->video[ v_idx ].bitrate = 400 * brate; + + byte mark; + while ( true ) { + offset = FindNextMarker( offset, &mark ); + if ( mark == MPEG_GOP_CODE ) + break; + switch ( GetByte( offset + 3 ) ) { + case MPEG_EXT_CODE : + // Extension + offset += 4; + switch ( GetByte( offset ) >> 4 ) { + case 1: + //SequenceExt + if ( GetByte( offset + 1 ) & 0x08 ) + mpeg_info->video[ v_idx ].progressive = true; + mpeg_info->video[ v_idx ].chroma_format = ( GetByte( offset + 1 ) & 0x06 ) >> 1; + break; + case 2: + // SequenceDisplayExt + mpeg_info->video[ v_idx ].video_format = ( GetByte( offset ) & 0x0E ) >> 1; + break; + } + + break; + case MPEG_USER_CODE : + // UserData + break; + } + offset++; + } + + mpeg_info->video[ v_idx ].seen = true; +} + +double K3bMpegInfo::ReadTS( llong offset ) +{ + byte highbit; + unsigned long low4Bytes; + double TS; + + highbit = ( GetByte( offset ) >> 3 ) & 0x01; + + low4Bytes = ( ( GetByte( offset ) >> 1 ) & 0x03 ) << 30; + low4Bytes |= GetByte( offset + 1 ) << 22; + low4Bytes |= ( GetByte( offset + 2 ) >> 1 ) << 15; + low4Bytes |= GetByte( offset + 3 ) << 7; + low4Bytes |= GetByte( offset + 4 ) >> 1; + + + TS = ( double ) ( highbit * FLOAT_0x10000 * FLOAT_0x10000 ); + TS += ( double ) ( low4Bytes ); + TS /= ( double ) ( STD_SYSTEM_CLOCK_FREQ ); + + return TS; +} + +double K3bMpegInfo::ReadTSMpeg2( llong offset ) +{ + byte highbit; + unsigned long low4Bytes; + unsigned long sys_clock_ref; + double TS; + + highbit = ( GetByte( offset ) & 0x20 ) >> 5; + + low4Bytes = ( ( GetByte( offset ) & 0x18 ) >> 3 ) << 30; + low4Bytes |= ( GetByte( offset ) & 0x03 ) << 28; + low4Bytes |= GetByte( offset + 1 ) << 20; + low4Bytes |= ( GetByte( offset + 2 ) & 0xF8 ) << 12; + low4Bytes |= ( GetByte( offset + 2 ) & 0x03 ) << 13; + low4Bytes |= GetByte( offset + 3 ) << 5; + low4Bytes |= ( GetByte( offset + 4 ) ) >> 3; + + sys_clock_ref = ( GetByte( offset + 4 ) & 0x3 ) << 7; + sys_clock_ref |= ( GetByte( offset + 5 ) >> 1 ); + + TS = ( double ) ( highbit * FLOAT_0x10000 * FLOAT_0x10000 ); + TS += ( double ) ( low4Bytes ); + if ( sys_clock_ref == 0 ) + TS /= ( double ) ( STD_SYSTEM_CLOCK_FREQ ); + else { + TS /= ( double ) ( 27000000 / sys_clock_ref ); + } + + return TS; +} |