1 /*************************************************************************
2 * mkv.c - Matroska reading code [part of AVInfo 1.x]
3 * data format from
4 * http://matroska.org/
5 *
6 * Copyright (c) 2004 George Shuklin
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program (see the file COPYING); if not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA or visit http://www.gnu.org/copyleft/gpl.html
22 *
23 *************************************************************************/
24
25
26 /* use a tabulation size 4 spaces for normal editig*/
27 #include "mkv.h"
28 #define BUFFER_SIZE 0x4000
29 #define MAX_STRING_SIZE 1024
30
VINTparse(const unsigned char * buffer,const int start,const int end,int64 * result,const int flag)31 int VINTparse(const unsigned char* buffer, const int start, const int end, int64 *result,const int flag){
32 /*���������� �� VINT (�� 㪠������� ᬥ饭��) � int64, �����頥� ࠧ��� (ᤢ��), flag=0 - elementID, 1 - size*/
33 const unsigned char mask[8]={0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1};
34 const unsigned char imask[8]={0x7F,0x3F,0x1F,0xF,0x7,0x3,0x1,00};
35 int VINT_WIDTH;
36 int c;
37 if(end-start<2) {printf("debug: oops, out of buffer(%d)\n",start);return 0; /*ops*/}
38 VINT_WIDTH=0;
39 for(c=0;c<8;c++)
40 if( !(buffer[start]&mask[c]) ) VINT_WIDTH++;
41 else break;
42 if(VINT_WIDTH>=8 || VINT_WIDTH+start+1>=end) {printf("debug: oops2\n");return 0;}
43 *result=0;
44 for(c=0;c<VINT_WIDTH;c++)
45 *result+=buffer[start+VINT_WIDTH-c]<<(c*8);
46 if(flag)
47 *result+=(buffer[start]&imask[VINT_WIDTH])<<(VINT_WIDTH*8);
48 else *result+=(buffer[start])<<(VINT_WIDTH*8);
49 return VINT_WIDTH+1;
50 }
51
ElementRead(const unsigned char * buffer,const int start,const int end,unsigned int * ID,int64 * size)52 int ElementRead(const unsigned char* buffer, const int start, const int end, unsigned int* ID, int64* size){
53 int64 tempID;
54 int64 tempsize;
55 int ID_offset,size_offset;
56 ID_offset=VINTparse(buffer,start,end,&tempID,0);
57 if(!ID_offset) return 0;
58 size_offset=VINTparse(buffer,start+ID_offset,end,&tempsize,1);
59 if(!size_offset) return 0;
60 *ID=(int)tempID; /*id must be <4 and must to feet in uint*/
61 *size=tempsize;
62 return ID_offset+size_offset;
63 }
64
GetInt(const unsigned char * buffer,const int start,const int size)65 int64 GetInt(const unsigned char* buffer,const int start, const int size){
66 /*return a int [8-64], from buffer, Big Endian*/
67 int64 result=0;
68 int c;
69 for(c=1;c<=size;c++){
70 result+=buffer[start+c-1]<<(8*(size-c));
71 }
72 return result;
73 }
74
GetFloat(const unsigned char * buffer,const int start,const int size)75 float GetFloat(const unsigned char* buffer, const int start, const int size){
76 float result=0;
77 unsigned char tmp[4];
78 if(size==sizeof(float)) {
79 tmp[0]=buffer[start+3];
80 tmp[1]=buffer[start+2];
81 tmp[2]=buffer[start+1];
82 tmp[3]=buffer[start];
83 result=*((float*)(tmp));
84 }
85 return result;
86 }
87
88 const unsigned int MKV_Parse_list[]={/*Elements, containing requed information (sub-elements), see enum in mkv.h for values*/
89 MKVID_Segment,
90 MKVID_Info,
91 MKVID_Video,
92 MKVID_Audio,
93 MKVID_TrackEntry,
94 MKVID_Tracks
95 };
96
97 const char stream_type_letters[]="!vat";
98
mkvparse(FILE * file,int s)99 int mkvparse(FILE* file, int s){
100
101 unsigned char* buffer=malloc(BUFFER_SIZE+128);
102 unsigned int video[MAX_STREAMS][VIDEO_INFO_SIZE];
103 unsigned int audio[MAX_STREAMS][AUDIO_INFO_SIZE];
104 char* lang[MAX_STREAMS][4];/*1 - video, 2 - audio, 3 - text, 0 unused*/
105 char* codec[MAX_STREAMS][4];/*1 - video, 2 - audio, 3 - text, 0 unused*/
106 int p; /*pointer in buffer*/
107 int c,c2; /*counter in some loops*/
108 int readed_bytes;
109 unsigned int eID; /*element ID*/
110 int64 eSize; /*Size of element content*/
111 int offs;
112 char* title=NULL;
113 int64 timescale=1000000;
114 float Duration=0;
115 char* tstr1, *tstr2; /*temp strings*/
116 int64 DefaultDuration=0;
117 int TrackType=0;
118 int pvt_look_flag=0;
119 int curr_c=-1;
120 int a_c=-1;
121 int v_c=-1;
122 int t_c=-1;
123 int value=0;
124
125 if(!buffer) return 0;
126 memset(video,0,sizeof(video));
127 memset(audio,0,sizeof(audio));
128 memset(lang,0,sizeof(lang));
129 memset(codec,0,sizeof(codec));
130
131 readed_bytes=fread(buffer,1,BUFFER_SIZE,file); /*todo buffer_size,1 ? */
132 if(!readed_bytes){free(buffer);return 0;}
133 p=0;
134 while(buffer[p]!=MKVID_FILE_BEGIN){
135 p++;
136 if(p>=readed_bytes){
137 free(buffer);
138 return 0;
139 }
140 }; /*skip text while EBML begin*/
141
142 /*main loop*/
143 do{
144 offs=ElementRead(buffer,p,readed_bytes,&eID,&eSize);
145 p+=offs;
146 if(!offs||p>=readed_bytes) break;
147 for(c=0;c<sizeof(MKV_Parse_list)/sizeof(*MKV_Parse_list);c++)
148 if(MKV_Parse_list[c]==eID) {
149 break;
150 }
151 if(c<sizeof(MKV_Parse_list)/sizeof(*MKV_Parse_list)) continue;
152 if(p+eSize>readed_bytes) break; /*TODO - add (if requied) suckup from file to buffer*/
153 if(eSize==4||eSize==8||eSize==1||eSize==2)
154 value=(int)GetInt(buffer,p,eSize);
155 switch(eID){
156 case MKVID_TrackType: /*detect a stream type (video/audio/text)*/
157 TrackType=value;
158 pvt_look_flag=0;
159 switch(TrackType){
160 case MKV_Track_video:
161 v_c++;
162 if(v_c>MAX_STREAMS) v_c=MAX_STREAMS;
163 video[v_c][V_exist]=1;
164 video[v_c][V_l]=(int)(Duration/1e+9*(float)timescale);
165 curr_c=v_c;
166 break;
167 case MKV_Track_audio:
168 a_c++;
169 if(a_c>MAX_STREAMS) a_c=MAX_STREAMS;
170 audio[a_c][A_exist]=1;
171 audio[a_c][A_l]=(int)(Duration/1e+9*(float)timescale);
172 curr_c=a_c;
173 break;
174 case MKV_Track_subtitle_orig:
175 t_c++;
176 TrackType=MKV_Track_subtitle; /*for normal use in lang array*/
177 if(t_c>MAX_STREAMS) t_c=MAX_STREAMS;
178 curr_c=t_c;
179 break;
180 }
181 break;
182 case MKVID_DefaultDuration: /*fps detection*/
183 if(TrackType==MKV_Track_video&&v_c>=0){
184 DefaultDuration=value;
185 if(DefaultDuration>100){
186 video[v_c][V_fpsH]=1000000000/DefaultDuration; /*DD in nano sec. fps=1s/DD*/
187 video[v_c][V_fpsL]=1000000000/(DefaultDuration/100)-100*video[v_c][V_fpsH];
188 }
189 }
190 break;
191 case MKVID_Language: /*stream language*/
192 if(curr_c>=0&&TrackType<4&&eSize<MAX_STRING_SIZE)
193 if(lang[curr_c][TrackType]) free(lang[curr_c][TrackType]);
194 lang[curr_c][TrackType]=mkstr(buffer,p,eSize);
195 break;
196 case MKVID_CodecName:/*passtrough*/
197 case MKVID_CodecID: /*codec detection (if V_MS/VFW/FOURCC - set a fourcc code, else fill a vcodecs value)*/
198 if(curr_c>=0&&TrackType<4&&eSize<MAX_STRING_SIZE){
199 if(codec[curr_c][TrackType]) free(codec[curr_c][TrackType]);
200 codec[curr_c][TrackType]=mkstr(buffer,p,eSize);
201 if(!strcmp(codec[curr_c][TrackType],"V_MS/VFW/FOURCC")) pvt_look_flag=1;
202 }
203 break;
204 case MKVID_CodecPrivate:
205 if(pvt_look_flag&&v_c>=0&&eSize>=24){ /*CodecPrivate contains a BITMAPINFOHEADER structure due CodecID==V_MS/VFW/FOURCC*/
206 pvt_look_flag=0;
207 video[v_c][V_cc]=(buffer[p+16]<<24)+(buffer[p+17]<<16)+(buffer[p+18]<<8)+buffer[p+19];
208 if(codec[v_c][MKV_Track_video]){
209 free(codec[v_c][MKV_Track_video]);
210 codec[v_c][MKV_Track_video]=NULL;
211 }
212 }
213 break;
214 case MKVID_PixelWidth: /*pasthough*/
215 case MKVID_DisplayWidth:
216 if(v_c>=0)video[v_c][V_x]=value;
217 break;
218 case MKVID_PixelHeight: /*pasthough*/
219 case MKVID_DisplayHeight:
220 if(v_c>=0)video[v_c][V_y]=value;
221 break;
222 case MKVID_TimeCodeScale:
223 timescale=GetInt(buffer,p,eSize);
224 break;
225 case MKVID_Duration:
226 Duration=GetFloat(buffer,p,eSize);
227 break;
228 case MKVID_Channels:
229 if(a_c>=0)audio[a_c][A_ch]=value;
230 break;
231 case MKVID_BitDepth:
232 if(a_c>=0)audio[a_c][A_bits]=value;
233 break;
234 case MKVID_OutputSamplingFrequency: /*pasthough*/
235 case MKVID_SamplingFrequency:
236 if(a_c>=0) audio[a_c][A_freq]=(int)GetFloat(buffer,p,eSize);
237 break;
238 case MKVID_Title:
239 if(eSize>MAX_STRING_SIZE) break;
240 title=mkstr(buffer,p,eSize);
241 SetNumericVar("stream.d",1);
242 SetNumericVar("d1.num",1);
243 SetStringVar("d11.name","Title");
244 SetStringVar("d11.value",title);
245 free(title);
246 break;
247 /*TODO case MKVID_Tags:*/
248 }
249 p+=eSize;/*skip unknown or uninteresting*/
250 }while(1);
251 AddAudioVideo(video,audio);
252 tstr1=dup("dn.lang");
253 tstr2=dup("dn.cc");
254 if(tstr1&&tstr2){
255 for(c=0;c<MAX_STREAMS;c++){
256 for(c2=0;c2<4;c2++){
257 tstr1[0]=stream_type_letters[c2];
258 tstr1[1]=c+'0'+1;
259 tstr2[1]=tstr1[1];
260 tstr2[0]=tstr1[0];
261 if(lang[c][c2]){
262 SetStringVar(tstr1,lang[c][c2]);
263 free(lang[c][c2]);
264 }
265 if(codec[c][c2]){
266 SetStringVar(tstr2,codec[c][c2]);
267 free(codec[c][c2]);
268 }
269 }
270 }
271 SetNumericVar("stream.t",t_c+1);
272 free(tstr1);
273 free(tstr2);
274 }
275 if(buffer) free(buffer);
276 return 1;
277 }
278