Ejemplo n.º 1
0
static void AudioTrack(format_stream* s,TrackInfo* Info,int Format,bool_t PacketBased)
{
	PacketFormatClear(&s->Format);
	s->Format.Type = PACKET_AUDIO;
	s->Format.Format.Audio.Format = Format;
	Info->AV.Audio.Channels;
	s->Format.Format.Audio.Channels = Info->AV.Audio.Channels; //Mod2010:
	s->Format.Format.Audio.SampleRate = mkv_TruncFloat(Info->AV.Audio.SamplingFreq); //Mod2010:
	s->Format.Format.Audio.Bits = Info->AV.Audio.BitDepth; //Mod2010:
	s->Fragmented = !PacketBased;
	if (PacketBased)
		s->Format.Format.Audio.Flags |= PCM_PACKET_BASED;
	PacketFormatDefault(&s->Format);
}
Ejemplo n.º 2
0
void InitializeCodecContextFromMatroskaTrackInfo(TrackInfo *TI, AVCodecContext *CodecContext) {
	uint8_t *PrivateDataSrc = static_cast<uint8_t *>(TI->CodecPrivate);
	size_t PrivateDataSize = TI->CodecPrivateSize;
	size_t BIHSize = sizeof(FFMS_BITMAPINFOHEADER); // 40 bytes
	if (!strncmp(TI->CodecID, "V_MS/VFW/FOURCC", 15) && PrivateDataSize >= BIHSize) {
		// For some reason UTVideo requires CodecContext->codec_tag (i.e. the FourCC) to be set.
		// Fine, it can't hurt to set it, so let's go find it.
		// In a V_MS/VFW/FOURCC track, the codecprivate starts with a BITMAPINFOHEADER. If you treat that struct
		// as an array of uint32_t, the biCompression member (that's the FourCC) can be found at offset 4.
		// Therefore the following derp.
		CodecContext->codec_tag = reinterpret_cast<uint32_t *>(PrivateDataSrc)[4];

		// Now skip copying the BITMAPINFOHEADER into the extradata, because lavc doesn't expect it to be there.
		if (PrivateDataSize <= BIHSize) {
			PrivateDataSrc = NULL;
			PrivateDataSize = 0;
		}
		else {
			PrivateDataSrc += BIHSize;
			PrivateDataSize -= BIHSize;
		}
	}
	// I think you might need to do some special handling for A_MS/ACM extradata too,
	// but I don't think anyone actually uses that.

	if (PrivateDataSrc && PrivateDataSize > 0) {
		CodecContext->extradata = static_cast<uint8_t *>(av_mallocz(PrivateDataSize + FF_INPUT_BUFFER_PADDING_SIZE));
		CodecContext->extradata_size = PrivateDataSize;
		memcpy(CodecContext->extradata, PrivateDataSrc, PrivateDataSize);
	}

	if (TI->Type == TT_VIDEO) {
		CodecContext->coded_width = TI->AV.Video.PixelWidth;
		CodecContext->coded_height = TI->AV.Video.PixelHeight;
	} else if (TI->Type == TT_AUDIO) {
		CodecContext->sample_rate = mkv_TruncFloat(TI->AV.Audio.SamplingFreq);
		CodecContext->bits_per_coded_sample = TI->AV.Audio.BitDepth;
		CodecContext->channels = TI->AV.Audio.Channels;
	}
}
Ejemplo n.º 3
0
//////////////////
// Actually parse
void MatroskaWrapper::Parse() {
    // Clear keyframes and timecodes
    keyFrames.Clear();
    bytePos.Clear();
    timecodes.clear();

    // Get info
    int tracks = mkv_GetNumTracks(file);
    TrackInfo *trackInfo;
    SegmentInfo *segInfo = mkv_GetFileInfo(file);

    // Parse tracks
    for (int track=0; track<tracks; track++) {
        trackInfo = mkv_GetTrackInfo(file,track);

        // Video track
        if (trackInfo->Type == 1) {
            // Variables
            ulonglong startTime, endTime, filePos;
            unsigned int rt, frameSize, frameFlags;
            CompressedStream *cs = NULL;

            // Timecode scale
            __int64 timecodeScale = mkv_TruncFloat(trackInfo->TimecodeScale) * segInfo->TimecodeScale;

            // Mask other tracks away
            mkv_SetTrackMask(file, ~(1 << track));

            // Progress bar
            int totalTime = double(segInfo->Duration) / timecodeScale;
            volatile bool canceled = false;
            DialogProgress *progress = new DialogProgress(NULL,_("Parsing Matroska"),&canceled,_("Reading keyframe and timecode data from Matroska file."),0,totalTime);
            progress->Show();
            progress->SetProgress(0,1);

            // Read frames
            int frameN = 0;
            while (mkv_ReadFrame(file,0,&rt,&startTime,&endTime,&filePos,&frameSize,&frameFlags) == 0) {
                // Read value
                double curTime = double(startTime) / 1000000.0;
                frames.push_back(MkvFrame((frameFlags & FRAME_KF) != 0,curTime,filePos));
                frameN++;

                // Cancelled?
                if (canceled) {
                    Close();
                    throw _T("Canceled");
                }

                // Update progress
                progress->SetProgress(curTime,totalTime);
            }

            // Clean up progress
            if (!canceled) progress->Destroy();

            break;
        }
    }

    // Copy raw
    for (std::list<MkvFrame>::iterator cur=frames.begin(); cur!=frames.end(); cur++) {
        rawFrames.push_back(*cur);
    }

    // Process timecodes and keyframes
    frames.sort();
    MkvFrame curFrame(false,0,0);
    int i = 0;
    for (std::list<MkvFrame>::iterator cur=frames.begin(); cur!=frames.end(); cur++) {
        curFrame = *cur;
        if (curFrame.isKey) keyFrames.Add(i);
        bytePos.Add(curFrame.filePos);
        timecodes.push_back(curFrame.time);
        i++;
    }
}
Ejemplo n.º 4
0
void MatroskaWrapper::GetSubtitles(agi::fs::path const& filename, AssFile *target) {
	MkvStdIO input(filename);
	char err[2048];
	agi::scoped_holder<MatroskaFile*, decltype(&mkv_Close)> file(mkv_Open(&input, err, sizeof(err)), mkv_Close);
	if (!file) throw MatroskaException(err);

	// Get info
	unsigned tracks = mkv_GetNumTracks(file);
	std::vector<unsigned> tracksFound;
	std::vector<std::string> tracksNames;

	// Find tracks
	for (auto track : boost::irange(0u, tracks)) {
		auto trackInfo = mkv_GetTrackInfo(file, track);
		if (trackInfo->Type != 0x11 || trackInfo->CompEnabled) continue;

		// Known subtitle format
		std::string CodecID(trackInfo->CodecID);
		if (CodecID == "S_TEXT/SSA" || CodecID == "S_TEXT/ASS" || CodecID == "S_TEXT/UTF8") {
			tracksFound.push_back(track);
			tracksNames.emplace_back(agi::format("%d (%s %s)", track, CodecID, trackInfo->Language));
			if (trackInfo->Name) {
				tracksNames.back() += ": ";
				tracksNames.back() += trackInfo->Name;
			}
		}
	}

	// No tracks found
	if (tracksFound.empty())
		throw MatroskaException("File has no recognised subtitle tracks.");

	unsigned trackToRead;
	// Only one track found
	if (tracksFound.size() == 1)
		trackToRead = tracksFound[0];
	// Pick a track
	else {
		int choice = wxGetSingleChoiceIndex(_("Choose which track to read:"), _("Multiple subtitle tracks found"), to_wx(tracksNames));
		if (choice == -1)
			throw agi::UserCancelException("canceled");

		trackToRead = tracksFound[choice];
	}

	// Picked track
	mkv_SetTrackMask(file, ~(1 << trackToRead));
	auto trackInfo = mkv_GetTrackInfo(file, trackToRead);
	std::string CodecID(trackInfo->CodecID);
	bool srt = CodecID == "S_TEXT/UTF8";
	bool ssa = CodecID == "S_TEXT/SSA";

	AssParser parser(target, !ssa);

	// Read private data if it's ASS/SSA
	if (!srt) {
		// Read raw data
		std::string priv((const char *)trackInfo->CodecPrivate, trackInfo->CodecPrivateSize);

		// Load into file
		boost::char_separator<char> sep("\r\n");
		for (auto const& cur : boost::tokenizer<boost::char_separator<char>>(priv, sep))
			parser.AddLine(cur);
	}
	// Load default if it's SRT
	else {
		target->LoadDefault(false, OPT_GET("Subtitle Format/SRT/Default Style Catalog")->GetString());
		parser.AddLine("[Events]");
	}

	// Read timecode scale
	auto segInfo = mkv_GetFileInfo(file);
	int64_t timecodeScale = mkv_TruncFloat(trackInfo->TimecodeScale) * segInfo->TimecodeScale;

	// Progress bar
	auto totalTime = double(segInfo->Duration) / timecodeScale;
	DialogProgress progress(nullptr, _("Parsing Matroska"), _("Reading subtitles from Matroska file."));
	progress.Run([&](agi::ProgressSink *ps) { read_subtitles(ps, file, &input, srt, totalTime, &parser); });
}
Ejemplo n.º 5
0
FFMatroskaVideo::FFMatroskaVideo(const char *SourceFile, int Track,
	FFMS_Index &Index, int Threads)
: FFMS_VideoSource(SourceFile, Index, Track, Threads)
, MF(0)
, Res(FFSourceResources<FFMS_VideoSource>(this))
, PacketNumber(0)
{
	AVCodec *Codec = NULL;
	TrackInfo *TI = NULL;

	MC.ST.fp = ffms_fopen(SourceFile, "rb");
	if (MC.ST.fp == NULL) {
		std::ostringstream buf;
		buf << "Can't open '" << SourceFile << "': " << strerror(errno);
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str());
	}

	setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);

	MF = mkv_OpenEx(&MC.ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage));
	if (MF == NULL) {
		std::ostringstream buf;
		buf << "Can't parse Matroska file: " << ErrorMessage;
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str());
	}

	TI = mkv_GetTrackInfo(MF, VideoTrack);

	if (TI->CompEnabled)
		TCC.reset(new TrackCompressionContext(MF, TI, VideoTrack));

	CodecContext = avcodec_alloc_context3(NULL);
	CodecContext->thread_count = DecodingThreads;

	Codec = avcodec_find_decoder(MatroskaToFFCodecID(TI->CodecID, TI->CodecPrivate));
	if (Codec == NULL)
		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
			"Video codec not found");

	InitializeCodecContextFromMatroskaTrackInfo(TI, CodecContext);

	if (avcodec_open2(CodecContext, Codec, NULL) < 0)
		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
			"Could not open video codec");

	Res.CloseCodec(true);

	// Always try to decode a frame to make sure all required parameters are known
	DecodeNextFrame();

	VP.FPSDenominator = 1;
	VP.FPSNumerator = 30;

	// Calculate the average framerate
	if (Frames.size() >= 2) {
		double PTSDiff = (double)(Frames.back().PTS - Frames.front().PTS);
		// Dividing by 1000 caused too much information to be lost, when CorrectNTSCRationalFramerate runs there was a possibility
		// of it outputting the wrong framerate.  We still divide by 100 to protect against the possibility of overflows.
		VP.FPSDenominator = (unsigned int)(PTSDiff * mkv_TruncFloat(TI->TimecodeScale) / (double)100 / (double)(Frames.size() - 1) + 0.5);
		VP.FPSNumerator = 10000000;
	}

	// Set the video properties from the codec context
	SetVideoProperties();

	// Output the already decoded frame so it isn't wasted
	OutputFrame(DecodeFrame);

	// Set AR variables
	VP.SARNum = TI->AV.Video.DisplayWidth * TI->AV.Video.PixelHeight;
	VP.SARDen = TI->AV.Video.DisplayHeight * TI->AV.Video.PixelWidth;

	// Set crop variables
	VP.CropLeft = TI->AV.Video.CropL;
	VP.CropRight = TI->AV.Video.CropR;
	VP.CropTop = TI->AV.Video.CropT;
	VP.CropBottom = TI->AV.Video.CropB;
}