1 
2 module macroblock;
3 
4 import std.exception;
5 import std.stdio;
6 import bitstream;
7 import vlc;
8 import decoder;
9 
10 enum PredictionType
11 {
12 	Field,
13 	Frame,
14 	DualPrime,
15 	Mc16x8,
16 }
17 
18 enum MvFormat
19 {
20 	Field,
21 	Frame,
22 }
23 
24 struct Block
25 {
26 	short[64] coeffs;
27 }
28 
29 struct MacroBlock
30 {
31 	Slice s;
32 	MbParams p;
33 	ubyte incr;
34 	uint type;
35 	ubyte spartial_temporal_weight_code;
36 	ubyte motion_type;
37 	ubyte dct_type;
38 	ubyte quantiser_scale_code;
39 	bool[2][2] motion_vertical_field_select;
40 	byte[2][2][2] motion_code;
41 	ubyte[2][2][2] motion_residual;
42 	ubyte[2] dmvector;
43 	uint coded_block_pattern;
44 	Block[12] blocks;
45 
46 	this(Slice s)
47 	{
48 		this.s = s;
49 	}
50 
51 	void parse(BitstreamReader bs)
52 	{
53 		int temp_incr = bs.read_mb_inc();
54 
55 		while(temp_incr == 34)
56 		{
57 			this.incr += 33;
58 			temp_incr = bs.read_mb_inc();
59 		}
60 
61 		this.incr += temp_incr;
62 
63 		parse_modes(bs);
64 
65 		if(p.quant)
66 		{
67 			this.quantiser_scale_code = cast(ubyte) bs.read_u(5);
68 		}
69 
70 		if(p.motion_forward || (p.intra && s.ph.concealment_motion_vectors))
71 		{
72 			parse_motion_vectors(bs, 0);
73 		}
74 
75 		if(p.motion_backward)
76 		{
77 			parse_motion_vectors(bs, 1);
78 		}
79 
80 		if(p.intra && s.ph.concealment_motion_vectors)
81 		{
82 			enforce(bs.read_u1 == 1, "marker bit");
83 		}
84 
85 		if(p.pattern)
86 		{
87 			parse_coded_block_pattern(bs);
88 		}
89 
90 		for(ubyte i=0; i< block_count(); ++i)
91 		{
92 			parse_block(bs, i);
93 		}
94 	}
95 
96 	ubyte block_count() const
97 	{
98 		immutable ubyte[] table = [
99 			0, // should not happen
100 			6,
101 			8,
102 			12,
103 		];
104 
105 		return table[s.ph.si.chroma_format];
106 	}
107 
108 	void parse_motion_vectors(BitstreamReader bs, ubyte s)
109 	{
110 		if(predinfo.motion_vector_count == 1)
111 		{
112 			if(predinfo.mv_format == MvFormat.Field && predinfo.dmv != 1)
113 			{
114 				motion_vertical_field_select[0][s] = bs.read_bool;
115 			}
116 
117 			parse_mv(bs, 0, s);
118 		}
119 		else
120 		{
121 			motion_vertical_field_select[0][s] = bs.read_bool;
122 			parse_mv(bs, 0, s);
123 			motion_vertical_field_select[1][s] = bs.read_bool;
124 			parse_mv(bs, 1, s);
125 		}
126 	}
127 
128 	void parse_mv(BitstreamReader bs, ubyte r, ubyte s)
129 	{
130 		motion_code[r][s][0] = bs.read_mc;
131 		if(this.s.ph.f_code[s][0] != 1 && motion_code[r][s][0] != 0)
132 		{
133 			motion_residual[r][s][0] = bs.read_b(this.s.ph.f_code[s][0] - 1);
134 		}
135 		if(predinfo.dmv == 1)
136 		{
137 			dmvector[0] = bs.read_dmvector();
138 		}
139 
140 		motion_code[r][s][1] = bs.read_mc;
141 		if(this.s.ph.f_code[s][1] != 1 && motion_code[r][s][1] != 0)
142 		{
143 			motion_residual[r][s][1] = bs.read_b(this.s.ph.f_code[s][1] - 1);
144 		}
145 		if(predinfo.dmv == 1)
146 		{
147 			dmvector[1] = bs.read_dmvector();
148 		}
149 	}
150 
151 	void parse_coded_block_pattern(BitstreamReader bs)
152 	{
153 		coded_block_pattern = bs.read_cbp();
154 		if(s.ph.si.chroma_format == ChromaFormat.C422)
155 		{
156 			coded_block_pattern <<= 2;
157 			coded_block_pattern |= bs.read_u(2);
158 		}
159 		if(s.ph.si.chroma_format == ChromaFormat.C444)
160 		{
161 			coded_block_pattern <<= 6;
162 			coded_block_pattern |= bs.read_u(6);
163 		}
164 	}
165 
166 	bool pattern_code(ubyte i)
167 	{
168 		if(p.pattern)
169 		{
170 			return cast(bool)(coded_block_pattern & (1 << (block_count() - 1 - i)));
171 		}
172 		else
173 		{
174 			return p.intra;
175 		}
176 	}
177 
178 	void parse_block(BitstreamReader bs, ubyte i)
179 	{
180 		if(!pattern_code(i)) return;
181 
182 		if(p.intra)
183 		{
184 			// TODO: optimize
185 			uint dc_size = bs.read_dc_size(i<4);
186 			short dct_diff = bs.read_u!short(dc_size);
187 
188 			if ((dct_diff & (1<<(dc_size-1)))==0)
189 			{
190 				dct_diff-= (1<<dc_size) - 1;
191 			}
192 
193 			//if(ddd >> (dc_size - 1))
194 			//{
195 			//	ddd = cast(short) (ddd + 1 - (1 << dc_size));
196 			//}
197 			blocks[i].coeffs[0] = dct_diff;
198 		}
199 
200 		short run, level;
201 		int idx = p.intra;
202 		bool eob = !bs.read_dct(idx == 0, run, level, s.ph.intra_vlc_format);
203 		while(!eob)
204 		{
205 			//writefln("block(%d): rl: (%d, %d) idx: %d", i, run, level, idx);
206 			idx += run;
207 			blocks[i].coeffs[idx] = level;
208 			++idx;
209 			eob = !bs.read_dct(false, run, level, s.ph.intra_vlc_format);
210 		}
211 	}
212 
213 	PredictionInfo predinfo() const
214 	{
215 		if(s.ph.picture_structure == PictureStructure.Frame)
216 		{
217 			if(s.ph.frame_pred_frame_dct == 0)
218 				return frame_prediction_info[motion_type][0];
219 			else
220 				return frame_prediction_info[2][0]; // Frame-based
221 		}
222 		else
223 		{
224 			return field_prediction_info[motion_type][0];
225 		}
226 	}
227 
228 	void parse_modes(BitstreamReader bs)
229 	{
230 		this.type = bs.read_mb_type(s.ph.picture_coding_type);
231 		this.p = mb_params[s.ph.picture_coding_type][this.type];
232 
233 		if(this.p.spartial_temporal_weight_code_flag
234 			/* TODO: && spatial_temporal_weight_code_table_index != 00 */
235 		)
236 		{
237 			throw new Exception("spartial prediction is not implemented");
238 			//this.spartial_temporal_weight_code = bs.read_u(8);
239 		}
240 
241 		if(this.p.motion_forward || this.p.motion_backward)
242 		{
243 			if(s.ph.picture_structure == PictureStructure.Frame)
244 			{
245 				if(s.ph.frame_pred_frame_dct == 0)
246 				{
247 					this.motion_type = bs.read_b(2);
248 				}
249 			}
250 			else
251 			{
252 				this.motion_type = bs.read_b(2);
253 			}
254 		}
255 
256 		if(s.ph.picture_structure == PictureStructure.Frame
257 			&& s.ph.frame_pred_frame_dct == 0
258 			&& (this.p.intra || this.p.pattern)
259 			)
260 		{
261 			this.dct_type = bs.read_u1;
262 		}
263 	}
264 
265 	void dump_block(int idx)
266 	{
267 		writefln("    block(%d):", idx);
268 		for(size_t i=0; i<8; ++i)
269 		{
270 			writef("        ");
271 			for(size_t j=0; j<8; ++j)
272 			{
273 				writef("%3d ", blocks[idx].coeffs[i*8+j]);
274 			}
275 			writefln("");
276 		}
277 	}
278 
279 	void dump(bool with_blocks = false)
280 	{
281 		auto mb = this;
282 
283 		writefln("macroblock:");
284 		writefln("    params   : %s", mb.p);
285 		writefln("    type     : %d", mb.type);
286 		writefln("    incr     : %d", mb.incr);
287 
288 		if(p.quant)
289 		{
290 			writefln("    type     : %d", mb.quantiser_scale_code);
291 		}
292 
293 		if(p.motion_forward || (p.intra && s.ph.concealment_motion_vectors))
294 		{
295 		}
296 
297 		if(p.motion_backward)
298 		{
299 		}
300 
301 		if(p.pattern)
302 		{
303 			writefln("    cbp      : %d", mb.coded_block_pattern);
304 		}
305 
306 		if(with_blocks)
307 		{
308 			for(ubyte i=0; i< block_count(); ++i)
309 			{
310 				dump_block(i);
311 			}
312 		}
313 	}
314 
315 	void dump2(int mba, bool with_blocks) const
316 	{
317 		writefln("mb.incr: %d MBA: %d cbp: %d", incr, mba, coded_block_pattern);
318 
319 		if(!with_blocks) return;
320 
321 		for(ubyte bidx=0; bidx< block_count(); ++bidx)
322 		{
323 			writefln("MBA #%d block #%d: ", mba, bidx);
324 
325 			for(size_t i=0; i<8; ++i)
326 			{
327 				writef("    ");
328 				for(size_t j=0; j<8; ++j)
329 				{
330 					writef("%3d ", blocks[bidx].coeffs[i*8+j]);
331 				}
332 				writeln();
333 			}
334 			writeln();
335 		}
336 
337 	}
338 }
339 
340 struct MbParams
341 {
342 	bool quant;
343 	bool motion_forward;
344 	bool motion_backward;
345 	bool pattern;
346 	bool intra;
347 	bool spartial_temporal_weight_code_flag;
348 	uint permitted_spatial_temporal_weight_classes;
349 
350 	string toString()
351 	{
352 		string s = "";
353 
354 		if(quant) s ~= "quant,";
355 		if(motion_forward) s ~= "motion_forward,";
356 		if(motion_backward) s ~= "motion_backward,";
357 		if(pattern) s ~= "pattern,";
358 		if(intra) s ~= "intra,";
359 		if(spartial_temporal_weight_code_flag) s ~= "spartial_temporal_weight_code_flag,";
360 
361 		if(s.length > 0)
362 			s = s[0..$-1];
363 
364 		return s;
365 	}
366 }
367 
368 struct PredictionInfo
369 {
370 	PredictionType type;
371 	ubyte motion_vector_count;
372 	MvFormat mv_format;
373 	bool dmv;
374 }
375 
376 // Table 6-17
377 static immutable PredictionInfo[4][4] frame_prediction_info = [
378 	[
379 		{PredictionType.Frame, 1, MvFormat.Field, 0},
380 	],
381 	[
382 		{PredictionType.Field, 2, MvFormat.Field, 0},
383 		{PredictionType.Field, 2, MvFormat.Field, 0},
384 		{PredictionType.Field, 1, MvFormat.Field, 0},
385 		{PredictionType.Field, 1, MvFormat.Field, 0},
386 	],
387 	[
388 		{PredictionType.Frame, 1, MvFormat.Frame, 0},
389 		{PredictionType.Frame, 1, MvFormat.Frame, 0},
390 		{PredictionType.Frame, 1, MvFormat.Frame, 0},
391 		{PredictionType.Frame, 1, MvFormat.Frame, 0},
392 	],
393 	[
394 		{PredictionType.DualPrime, 1, MvFormat.Field, 1},
395 		{},
396 		{PredictionType.DualPrime, 1, MvFormat.Field, 1},
397 		{PredictionType.DualPrime, 1, MvFormat.Field, 1},
398 	],
399 ];
400 
401 // Table 6-18
402 static immutable PredictionInfo[2][4] field_prediction_info = [
403 	[
404 		{PredictionType.Field, 1, MvFormat.Field, 0},
405 	],
406 	[
407 		{PredictionType.Field, 1, MvFormat.Field, 0},
408 		{PredictionType.Field, 1, MvFormat.Field, 0},
409 	],
410 	[
411 		{PredictionType.Mc16x8, 2, MvFormat.Field, 0},
412 		{PredictionType.Mc16x8, 2, MvFormat.Field, 0},
413 	],
414 	[
415 		{PredictionType.DualPrime, 1, MvFormat.Field, 1},
416 	],
417 ];
418 
419 // Table B.2
420 immutable MbParams[] mb_params_I = [
421 	{0,0,0,0,1,0,0},
422 	{1,0,0,0,1,0,0},
423 ];
424 
425 // Table B.3
426 immutable MbParams[] mb_params_P = [
427 	{0,1,0,1,0,0,0},
428 	{0,0,0,1,0,0,0},
429 	{0,1,0,0,0,0,0},
430 	{0,0,0,0,1,0,0},
431 	{1,1,0,1,0,0,0},
432 	{1,0,0,1,0,0,0},
433 	{1,0,0,0,1,0,0},
434 ];
435 
436 // Table B.4
437 immutable MbParams[] mb_params_B = [
438 	{0,1,1,0,0,0,0},
439 	{0,1,1,1,0,0,0},
440 	{0,0,1,0,0,0,0},
441 	{0,0,1,1,0,0,0},
442 	{0,1,0,0,0,0,0},
443 	{0,1,0,1,0,0,0},
444 	{0,0,0,0,1,0,0},
445 	{1,1,1,1,0,0,0},
446 	{1,1,0,1,0,0,0},
447 	{1,0,1,1,0,0,0},
448 	{1,0,0,0,1,0,0},
449 ];
450 
451 // TODO:
452 // Table B.5-8
453 
454 
455 immutable MbParams[][] mb_params = [
456 	[],
457 	mb_params_I,
458 	mb_params_P,
459 	mb_params_B,
460 ];