:
The sample file is 8 bit (not 10 bit), and the storage format is tricky.
The tool allows you selecting the format.
The suitable format is as follows:
The frame is divided to two fields - upper filed and lower filed (interlace format).
Resolution of each filed is 176x72.
Because the format is YUV420, the size of U and V fields is 88x36.
The code sample uses the following stages:
- Read the upper filed of Y, U and V (8 bits per element).
- Read the lower filed of Y, U and V.
- Interleave upper and lower filed.
- Up-sample U and V to the size of Y.
- Convert YUV to RGB (use existing MATLAB function
ycbcr2rgb
).
The following code sample reads the first frame and convert to RGB:
fname = 'tulips_yuv420_inter_planar_qcif.yuv'; width = 176; height = 144; fid = fopen(fname, 'r'); % Open the video file Y0 = (fread(fid, [width, height/2], 'uint8'))'; %Read upper field of Y plane U0 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of Y plane V0 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read upper field of U plane Y1 = (fread(fid, [width, height/2], 'uint8'))'; %Read upper field of Y plane U1 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of U plane V1 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of V plane fclose(fid); %Interleave upper and lower fields Y = zeros(height, width); Y(1:2:end, :) = Y0; Y(2:2:end, :) = Y1; U = zeros(height/2, width/2); U(1:2:end, :) = U0; U(2:2:end, :) = U1; V = zeros(height/2, width/2); V(1:2:end, :) = V0; V(2:2:end, :) = V1; U = imresize(U, size(Y), 'bicubic'); V = imresize(V, size(Y), 'bicubic'); YUV = cat(3, Y, U, V); %Convert YUV to RGB (MATLAB function ycbcr2rgb uses BT.601 conversion formula). RGB = ycbcr2rgb(uint8(YUV)); figure,imshow(RGB)
Result:
Reading 10 bit YUV420:
Assumptions:
- Each 10 bits component is stored in 2 bytes (no "bits packing").
- Data is stored in lower part of each byte (each
uint16
element holds a value in range [0, 1023]).
- Storage format is the same non-standard interlace format as the
uint8
sample.
Build 10 bits YUV420 sample file from the 8 bits sample (singe frame for testing):
The following code build a 10 bits sample out of the 8 bits sample (expands the range from 8 bits stored in uint8
to 10 bits stored in uint16
).
fname = 'tulips_yuv420_inter_planar_qcif.yuv'; width = 176; height = 144; fid = fopen(fname, 'r'); % Open the video file Y0 = (fread(fid, [width, height/2], 'uint8'))'; %Read upper field of Y plane U0 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of Y plane V0 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read upper field of U plane Y1 = (fread(fid, [width, height/2], 'uint8'))'; %Read upper field of Y plane U1 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of U plane V1 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of V plane fclose(fid); fid = fopen('10bits__tulips_yuv420_inter_planar_qcif.yuv', 'w'); % Open for writing fwrite(fid, uint16(Y0'*(1023/255)), 'uint16'); %1023 = 2^10-1, and 255 = 2^8-1 fwrite(fid, uint16(U0'*(1023/255)), 'uint16'); fwrite(fid, uint16(V0'*(1023/255)), 'uint16'); fwrite(fid, uint16(Y1'*(1023/255)), 'uint16'); fwrite(fid, uint16(U1'*(1023/255)), 'uint16'); fwrite(fid, uint16(V1'*(1023/255)), 'uint16'); fclose(fid);
Reading 10 bit YUV420
The following code reads single frame of 10 bit YUV420 (matching list of assumptions):
fname = '10bits__tulips_yuv420_inter_planar_qcif.yuv'; width = 176; height = 144; fid = fopen(fname, 'r'); % Open the video file Y0 = (fread(fid, [width, height/2], 'uint16'))'; %Read upper field of Y plane U0 = (fread(fid, [width/2, height/4], 'uint16'))'; %Read lower field of Y plane V0 = (fread(fid, [width/2, height/4], 'uint16'))'; %Read upper field of U plane Y1 = (fread(fid, [width, height/2], 'uint16'))'; %Read upper field of Y plane U1 = (fread(fid, [width/2, height/4], 'uint16'))'; %Read lower field of U plane V1 = (fread(fid, [width/2, height/4], 'uint16'))'; %Read lower field of V plane fclose(fid); %Interleave upper and lower fields Y = zeros(height, width); Y(1:2:end, :) = Y0; Y(2:2:end, :) = Y1; U = zeros(height/2, width/2); U(1:2:end, :) = U0; U(2:2:end, :) = U1; V = zeros(height/2, width/2); V(1:2:end, :) = V0; V(2:2:end, :) = V1; U = imresize(U, size(Y), 'bicubic'); V = imresize(V, size(Y), 'bicubic'); YUV = cat(3, Y, U, V); %Convert elements range from [0, 1023] to range [0, 1] (MATLAB function ycbcr2rgb supports doubles in range [0, 1]). YUV = YUV/1023; %1023 applies 10 bits range. 2^10-1 = 1023 %Convet YUV to RGB (MATLAB function ycbcr2rgb uses BT.601 conversion formula). RGB = ycbcr2rgb(YUV); %Convert from double to uint8 (from range [0, 1] to range [0, 255]). RGB = im2uint8(RGB); figure,imshow(RGB)
Note:
The code YUV = YUV/1023
converts the "10 bits" format to [0, 1] double
format.
Conversion is used because ycbcr2rgb
is not supporting 10 bits input.
Computing the size of the file:
You are correct: "The size of one frame equals 1.5*the size of Y".
Assuming 10 bits component is stored in 2 bytes, size of Y is width*height*2, and size of one frame is width*height*3.