summaryrefslogtreecommitdiffstats
path: root/kfile-plugins/mpeg/kfile_mpeg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kfile-plugins/mpeg/kfile_mpeg.cpp')
-rw-r--r--kfile-plugins/mpeg/kfile_mpeg.cpp582
1 files changed, 0 insertions, 582 deletions
diff --git a/kfile-plugins/mpeg/kfile_mpeg.cpp b/kfile-plugins/mpeg/kfile_mpeg.cpp
deleted file mode 100644
index 4d51f64d..00000000
--- a/kfile-plugins/mpeg/kfile_mpeg.cpp
+++ /dev/null
@@ -1,582 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2005 Allan Sandfeld Jensen <kde@carewolf.com>
- *
- * 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 version 2.
- *
- * 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-// MPEG KFile plugin
-// Based on reading sourcecode of mpeglib, xinelib and libmpeg3
-// and studying MPEG dumps.
-
-#include <config.h>
-#include "kfile_mpeg.h"
-
-#include <kprocess.h>
-#include <klocale.h>
-#include <kgenericfactory.h>
-#include <kstringvalidator.h>
-#include <kdebug.h>
-
-#include <tqdict.h>
-#include <tqvalidator.h>
-#include <tqcstring.h>
-#include <tqfile.h>
-#include <tqdatetime.h>
-
-// #include <iostream>
-
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-
-typedef KGenericFactory<KMpegPlugin> MpegFactory;
-
-K_EXPORT_COMPONENT_FACTORY(kfile_mpeg, MpegFactory( "kfile_mpeg" ))
-
-KMpegPlugin::KMpegPlugin(TQObject *parent, const char *name,
- const TQStringList &args)
-
- : KFilePlugin(parent, name, args)
-{
- KFileMimeTypeInfo* info = addMimeTypeInfo( "video/mpeg" );
-
- KFileMimeTypeInfo::GroupInfo* group = 0L;
-
- group = addGroupInfo(info, "Technical", i18n("Technical Details"));
-
- KFileMimeTypeInfo::ItemInfo* item;
-
- item = addItemInfo(group, "Length", i18n("Length"), TQVariant::Int);
- setUnit(item, KFileMimeTypeInfo::Seconds);
-
- item = addItemInfo(group, "Resolution", i18n("Resolution"), TQVariant::Size);
-
- item = addItemInfo(group, "Frame rate", i18n("Frame Rate"), TQVariant::Double);
- setSuffix(item, i18n("fps"));
-
- item = addItemInfo(group, "Video codec", i18n("Video Codec"), TQVariant::String);
- item = addItemInfo(group, "Audio codec", i18n("Audio Codec"), TQVariant::String);
-
- item = addItemInfo(group, "Aspect ratio", i18n("Aspect ratio"), TQVariant::String);
-}
-
-// Frame-rate table from libmpeg3
-float frame_rate_table[16] =
-{
- 0.0, /* Pad */
- (float)24000.0/1001.0, /* Official frame rates */
- (float)24.0,
- (float)25.0,
- (float)30000.0/1001.0,
- (float)30.0,
- (float)50.0,
- (float)60000.0/1001.0,
- (float)60.0,
-
- 1, /* Unofficial economy rates */
- 5,
- 10,
- 12,
- 15,
- 0,
- 0,
-};
-
-/* Bitrate indexes */
-int bitrate_123[3][16] =
- { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,},
- {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,},
- {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} };
-
-static const uint16_t sequence_start = 0x01b3;
-static const uint16_t ext_sequence_start = 0x01b5;
-static const uint16_t gop_start = 0x01b8;
-static const uint16_t audio1_packet = 0x01c0;
-static const uint16_t audio2_packet = 0x01d0;
-static const uint16_t private1_packet = 0x01bd;
-static const uint16_t private2_packet = 0x01bf;
-
-int KMpegPlugin::parse_seq() {
- uint32_t buf;
- dstream >> buf;
-
- horizontal_size = (buf >> 20);
- vertical_size = (buf >> 8) & ((1<<12)-1);
- aspect_ratio = (buf >> 4) & ((1<<4)-1);
- int framerate_code = buf & ((1<<4)-1);
- frame_rate = frame_rate_table[framerate_code];
-
- dstream >> buf;
-
- bitrate = (buf >> 14);
-// kdDebug(7034) << "bitrate: " << bitrate << endl;
- bool has_intra_matrix = buf & 2;
- bool has_non_intra_matrix = buf & 1;
-
- int matrix = 0;
- if (has_intra_matrix) matrix +=64;
- if (has_non_intra_matrix) matrix +=64;
-
- mpeg = 1;
- return matrix;
-}
-
-void KMpegPlugin::parse_seq_ext() {
- uint32_t buf;
- dstream >> buf;
-
- uint8_t type = buf >> 28;
- if (type == 1)
- mpeg = 2;
-
- /*
- else
- if (type == 2) {
- dstream >> buf;
- // These are display-sizes. I let them override physical sizes.
- horizontal_size = (buf >> 18);
- vertical_size = (buf >> 1) & ((1<<14)-1);
-} */
-}
-
-long KMpegPlugin::parse_gop() {
- uint32_t buf;
- dstream >> buf;
- dstream >> buf;
-
- int gop_hour = (buf>>26) & ((1<<5)-1);
- kdDebug(7034) << "gop_hour: " << gop_hour << endl;
- int gop_minute = (buf>>20) & ((1<<6)-1);
- kdDebug(7034) << "gop_minute: " << gop_minute << endl;
- int gop_second = (buf>>13) & ((1<<6)-1);
- kdDebug(7034) << "gop_second: " << gop_second << endl;
- int gop_frame = (buf>>7) & ((1<<6)-1);
- kdDebug(7034) << "gop_frame: " << gop_frame << endl;
-
- long seconds = gop_hour*60*60 + gop_minute*60 + gop_second;
- return (long)seconds;
-}
-
-int KMpegPlugin::parse_audio() {
- uint16_t len;
- dstream >> len;
-// kdDebug(7034) << "Length of audio packet: " << len << endl;
-
- uint8_t buf;
- int i = 0;
- for(i=0; i<20; i++) {
- dstream >> buf;
- if (buf == 0xff) {
- dstream >> buf;
- if ((buf & 0xe0) == 0xe0)
- goto found_sync;
- }
- }
- kdDebug(7034) << "MPEG audio sync not found" << endl;
- return len-i;
-
-found_sync:
-
- int layer = ((buf >> 1) & 0x3);
- if (layer == 1)
- audio_type = 3;
- else if (layer == 2)
- audio_type = 2;
- else if (layer == 3)
- audio_type = 1;
- else
- kdDebug(7034) << "Invalid MPEG audio layer" << endl;
-
- dstream >> buf;
- int bitrate_index = (buf & 0xf0) >> 4;
- audio_rate = bitrate_123[3-layer][bitrate_index];
-
- return len-3-i;
-}
-
-int KMpegPlugin::skip_packet() {
- uint16_t len;
- dstream >> len;
-// kdDebug(7034) << "Length of skipped packet: " << len << endl;
-
- return len;
-}
-
-int KMpegPlugin::skip_riff_chunk() {
- dstream.setByteOrder(TQDataStream::LittleEndian);
- uint32_t len;
- dstream >> len;
-// std::cerr << "Length of skipped chunk: " << len << std::endl;
-
- dstream.setByteOrder(TQDataStream::BigEndian);
- return len;
-}
-
-int KMpegPlugin::parse_private() {
- uint16_t len;
- dstream >> len;
-// kdDebug(7034) << "Length of private packet: " << len << endl;
-
- // Match AC3 packets
- uint8_t subtype;
- dstream >> subtype;
- subtype = subtype >> 4;
- if (subtype == 8) // AC3
- audio_type = 5;
- else
- if (subtype == 10) // LPCM
- audio_type = 7;
-
- return len-1;
-}
-
-bool KMpegPlugin::find_mpeg_in_cdxa()
-{
- int skip_len = 0;
- uint32_t magic;
- uint32_t data_len;
- // search for data chunk
- while (true) {
- dstream >> magic;
- if (magic != 0x64617461) { // "fmt "
- skip_len = skip_riff_chunk();
- if (!file.at(file.at()+skip_len)) return false;
- continue;
- } else {
- // size of chunk
- dstream >> data_len;
- int block = 0;
- // search for mpeg part
- while(block < 32) {
- // check for CDXA sync thingy
- dstream >> magic;
- // 00 ff ff ff ff ff ff ff ff ff ff ff 00
- if (magic == 0x00ffffff) {
-// std::cerr << "Found CD sync" << std::endl;
- // skip 20 bytes
- if (!file.at(file.at()+20)) return false;
- dstream >> magic;
- if (magic == 0x000001ba) {
-// std::cerr << "Found CDXA mpeg" << std::endl;
- return true;
- }
- else {
-// std::cerr << "CDXA block: #" <<block << ": " << magic << std::endl;
- if (!file.at(file.at()+2324)) return false;
- block++;
- continue;
- }
- } else {
-// std::cerr << "Incorrect CDXA block" << std::endl;
- // shouldn't happen
- return true;
- }
- }
- return false;
- }
- }
-}
-
-bool KMpegPlugin::read_mpeg()
-{
- mpeg = 0;
- audio_type = 0;
- audio_rate = 0;
-
- uint32_t magic;
- dstream >> magic;
- if (magic == 0x52494646) // == "RIFF"
- {
- dstream >> magic;
- dstream >> magic;
- if (magic != 0x43445841) { // 0x43445841 == "CDXA"
- kdDebug(7034) << "Unknown RIFF file" << endl;
- return false;
- } else {
- if (!find_mpeg_in_cdxa()) return false;
- }
- }
- else
- if (magic != 0x000001ba) {
- kdDebug(7034) << "Not a MPEG-PS file" << endl;
- return false;
- }
-// file.at(0);
-
- uint8_t byte;
- int skip_len = 0;
- int state = 0;
- int skimmed = 0;
- int video_len = 0;
- int searched = 0;
- bool video_found = false, audio_found = false, gop_found = false;
- // Search for MPEG packets
- for(int i=0; i < 2048; i++) {
- dstream >> byte;
- skimmed++;
- searched++;
- if (video_len > 0) video_len--;
- // Use a fast state machine to find 00 00 01 sync code
- switch (state) {
- case 0:
- if (byte == 0)
- state = 1;
- else
- state = 0;
- break;
- case 1:
- if (byte == 0)
- state = 2;
- else
- state = 0;
- break;
- case 2:
- if (byte == 0)
- state = 2;
- else
- if (byte == 1)
- state = 3;
- else
- state = 0;
- break;
- case 3: {
- skimmed -= 4;
- if (skimmed) {
-// kdDebug(7034) << "Bytes skimmed:" << skimmed << endl;
- skimmed = 0;
- }
-// kdDebug(7034) << "Packet of type:" << TQString::number(byte,16) << endl;
- switch (byte) {
- case 0xb3:
- if (video_found) break;
- skip_len = parse_seq();
- video_found = true;
- video_len -= 8;
- video_len -= skip_len;
- break;
- case 0xb5:
- parse_seq_ext();
- video_len -= 4;
- break;
- case 0xb8:
- /*
- if (!gop_found) {
- start_time = parse_gop();
- gop_found = true;
- kdDebug(7034) << "start_time: " << start_time << endl;
- }
- */
- /* nobreak */
- case 0x00:
- case 0x01:
- // skip the rest of the video data
- if (video_len > 0 && video_found)
- skip_len = video_len;
- break;
- /*
- case 0xb2:
- skip_len = parse_user();
- break;
- */
- case 0xba:
- skip_len = 8;
- break;
- case 0xbe:
- // padding
- skip_len = skip_packet();
- break;
- case 0xe0:
- // video data
- if (video_found)
- skip_len = skip_packet();
- else
- video_len = skip_packet();
- break;
- case 0xbd:
- case 0xbf:
- skip_len = parse_private();
- break;
- case 0xc0:
- case 0xd0:
- skip_len = parse_audio();
- audio_found = true;
- break;
- default:
-// kdDebug(7034) << "Unhandled packet of type:" << TQString::number(byte,16) << endl;
- break;
- }
- state = 0;
- break;
- }
- }
-
- if (video_found && audio_found /*&& gop_found*/) break;
- if (skip_len) {
- if (!file.at(file.at()+skip_len))
- return false;
- searched += skip_len;
- skip_len = 0;
- }
- }
- /*
- if (skimmed)
- kdDebug(7034) << "Bytes skimmed:" << skimmed << endl;
- kdDebug(7034) << "Bytes searched:" << searched << endl;
- */
-
- if (mpeg == 0) {
- kdDebug(7034) << "No sequence-start found" << endl;
- return false;
- }
- return true;
-}
-
-// Search for the last GOP packet and read the time field
-void KMpegPlugin::read_length()
-{
- end_time = 0;
- uint8_t byte;
- int state = 0;
- // Search for the last gop
- file.at(file.size()-1024);
- for(int j=1; j<64; j++) {
-// dstream.setDevice(&file);
-// dstream.setByteOrder(TQDataStream::BigEndian);
- for(int i=0; i<1024; i++) {
- dstream >> byte;
- switch (state) {
- case 0:
- if (byte == 0)
- state = 1;
- else
- state = 0;
- break;
- case 1:
- if (byte == 0)
- state = 2;
- else
- state = 0;
- case 2:
- if (byte == 0)
- state = 2;
- else
- if (byte == 1)
- state = 3;
- else
- state = 0;
- case 3:
- if (byte == 0xb8) {
- end_time = parse_gop();
- kdDebug(7034) << "end_time: " << end_time << endl;
- return;
- }
- state = 0;
- }
- }
- state = 0;
- file.at(file.size()-j*1024);
- }
- kdDebug(7034) << "No end GOP found" << endl;
-}
-
-bool KMpegPlugin::readInfo( KFileMetaInfo& info, uint /*what*/)
-{
- if ( info.path().isEmpty() ) // remote file
- return false;
-
- file.setName(info.path());
-
- // open file, set up stream and set endianness
- if (!file.open(IO_ReadOnly))
- {
- kdDebug(7034) << "Couldn't open " << TQFile::encodeName(info.path()).data() << endl;
- return false;
- }
-
- dstream.setDevice(&file);
- dstream.setByteOrder(TQDataStream::BigEndian);
-
- start_time = end_time = 0L;
-
- if (!read_mpeg()) {
- kdDebug(7034) << "read_mpeg() failed!" << endl;
- }
- else {
- KFileMetaInfoGroup group = appendGroup(info, "Technical");
-
- appendItem(group, "Frame rate", double(frame_rate));
-
- appendItem(group, "Resolution", TQSize(horizontal_size, vertical_size));
- /* The GOP timings are completely bogus
- read_length();
- if (end_time != 0) {
- //long total_frames = end_time-start_time + 1;
- long total_time = end_time;
- appendItem(group, "Length", int(total_time));
- }
- // and so is bitrate
- long total_time = file.size()/((bitrate+audio_rate)*50);
- appendItem(group, "Length", int(total_time));
- */
- if (mpeg == 1)
- appendItem(group, "Video codec", "MPEG-1");
- else
- appendItem(group, "Video codec", "MPEG-2");
-
- switch (audio_type) {
- case 1:
- appendItem(group, "Audio codec", "MP1");
- break;
- case 2:
- appendItem(group, "Audio codec", "MP2");
- break;
- case 3:
- appendItem(group, "Audio codec", "MP3");
- break;
- case 5:
- appendItem(group, "Audio codec", "AC3");
- break;
- case 7:
- appendItem(group, "Audio codec", "PCM");
- break;
- default:
- appendItem(group, "Audio codec", i18n("Unknown"));
- }
- // MPEG 1 also has an aspect ratio setting, but it works differently,
- // and I am not sure if it is used.
- if (mpeg == 2) {
- switch (aspect_ratio) {
- case 1:
- appendItem(group, "Aspect ratio", i18n("default"));
- break;
- case 2:
- appendItem(group, "Aspect ratio", "4/3");
- break;
- case 3:
- appendItem(group, "Aspect ratio", "16/9");
- break;
- case 4:
- appendItem(group, "Aspect ratio", "2.11/1");
- break;
- }
- }
- }
-
- file.close();
- return true;
-}
-
-#include "kfile_mpeg.moc"