aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_mp4/RawMediaReader.cpp
blob: 4d077a6b065ca798d449cce0f40a1d40e9b306dd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include "RawMediaReader.h"
#include "virtualIO.h"
#include <limits.h>

bool IsMyExtension(const wchar_t *filename);

int RawMediaReaderService::CreateRawMediaReader(const wchar_t *filename, ifc_raw_media_reader **out_reader)
{
	if (IsMyExtension(filename))
	{
		void *unicode_reader = CreateUnicodeReader(filename);
		if (!unicode_reader )
			return NErr_FileNotFound;

		MP4FileHandle mp4 = MP4ReadEx(filename, unicode_reader, &UnicodeIO);
		if (!mp4) 
		{
			DestroyUnicodeReader(unicode_reader);
			return NErr_Malformed;
		}


		RawMediaReader *reader = new RawMediaReader(mp4, unicode_reader);
		if (!reader)
		{
			MP4Close(mp4); 
			DestroyUnicodeReader(unicode_reader); 
			return NErr_OutOfMemory;
		}

		*out_reader = reader;
		return NErr_Success;
	}
	else
	{
		return NErr_False;
	}
}

#define CBCLASS RawMediaReaderService
START_DISPATCH;
CB(CREATERAWMEDIAREADER, CreateRawMediaReader);
END_DISPATCH;
#undef CBCLASS

RawMediaReader::RawMediaReader(MP4FileHandle file, void *reader) : file(file), reader(reader)
{
	track_num=0;
	number_of_tracks=MP4GetNumberOfTracks(file);
	current_track = MP4_INVALID_TRACK_ID;
	chunk_position=0;
	chunk_size=0;
	chunk_buffer=0;
}

RawMediaReader::~RawMediaReader()
{
	if (chunk_buffer)
		MP4Free(chunk_buffer);
	MP4Close(file); 
	DestroyUnicodeReader(reader);
}

int RawMediaReader::ReadNextChunk()
{
again:
	/* see if it's time to cycle to the next track */
	if (current_track == MP4_INVALID_TRACK_ID)
	{
		if (track_num == number_of_tracks)
			return NErr_EndOfFile;

		current_track = MP4FindTrackId(file, track_num);
		if (current_track == MP4_INVALID_TRACK_ID)
			return NErr_EndOfFile;

		track_num++;

		const char* trackType = MP4GetTrackType(file, current_track);
		if (!MP4_IS_AUDIO_TRACK_TYPE(trackType) && !MP4_IS_VIDEO_TRACK_TYPE(trackType))
		{
			current_track = MP4_INVALID_TRACK_ID;
			goto again;
		}

		chunk_id = 1;
		number_of_chunks= MP4GetTrackNumberOfChunks(file, current_track);		
	}

	/* see if we've read all of our samples */
	if (chunk_id > number_of_chunks)
	{
		current_track = MP4_INVALID_TRACK_ID;
		goto again;
	}

	bool readSuccess = MP4ReadChunk(file, current_track, chunk_id, &chunk_buffer, &chunk_size);
	if (!readSuccess)
		return NErr_Error;

	chunk_position=0;
	chunk_id++;
	return NErr_Success;
}

int RawMediaReader::Read(void *buffer, size_t buffer_size, size_t *bytes_read)
{
	if (buffer_size > INT_MAX)
		return NErr_BadParameter;

	if (chunk_position==chunk_size)
	{
		MP4Free(chunk_buffer);
		chunk_buffer=0;
	}

	if (!chunk_buffer)
	{
		int ret = ReadNextChunk();
		if (ret != NErr_Success)
			return ret;
	}

	size_t to_read = chunk_size-chunk_position;
	if (to_read > buffer_size)
		to_read = buffer_size;

	memcpy(buffer, &chunk_buffer[chunk_position], to_read);
	chunk_position += to_read;
	*bytes_read = to_read;
	return NErr_Success;
}

size_t RawMediaReader::Release()
{
	delete this;
	return 0;
}

#define CBCLASS RawMediaReader
START_DISPATCH;
CB(RELEASE, Release);
CB(RAW_READ, Read);
END_DISPATCH;
#undef CBCLASS