ilia3101 / LibMLV

MLV Reading/Writing library
5 stars 0 forks source link

Adding new matrices #5

Open 2blackbar opened 2 years ago

2blackbar commented 2 years ago

I wanted to add new matrice "MotionCam", { 0.0127, 0.0727, 0.5789, -0.2806, 1.0683, 0.2451, 1.2341, -0.6660, 0.0994 }, { -0.0558, 0.1620, 0.5206, -0.3982, 1.2675, 0.1412, 1.0612, -0.4169, -0.1001 } }, {

But structure of raw2mlv changed so much im unable to compile windows exe, can someone help with that ? I wanted to add this new matrice , its for enabling motioncam dng files to be read by mlvapp after conversion, it records 4k dng video on a phone so i really want to get it working nicely .Also im not sure if it doesnt have r/g/b channels swapped so... i was able to pinpoint that out , anyway here is dng file : https://drive.google.com/file/d/1PTRT0ZH15ylJwobYu6MwhLsE6kjJ_9U6/view?usp=sharing

Can someone help me to get it working nicely in mlvapp, i mean the colour matrix, its currently swapped so the one i posted might be better. If not then this is original one from exiftool , and maybe swapping these will help cause they have swapped channels as is but the one i posted on top should work i believe: Color Matrix 1 : 0.8321 -0.1664 -0.1268 -0.6419 1.5928 0.0317 - 0.1743 0.3566 0.4755 Color Matrix 2 : 1.5469 -0.7578 -0.1953 -0.7109 1.8672 -0.2266 -0.0859 0.2422 0.5547

Its very weird, i tried to edit values in exiftool, they are changed, identical to pixel2 matrice file, but after raw2mlv its still rgb swapped in mlvapp, i dont get it , what do i need to change with exiftool.

masc4ii commented 2 years ago
Bildschirmfoto 2021-12-21 um 22 40 24

But manually change CFA to 0x01000201 makes it not much better.

2blackbar commented 2 years ago

heres one that has it changed but in my opinion, blue channel is just missing, and the blue thats in mlv file is just a clone of red, i dont know, in other examples i could see swapped colours but all 3 were there, and here im just getting two tones. painnnt.zip

masc4ii commented 2 years ago

That worked in terms of this CFA value - it is inside the MLV now. But the image looks as in my screenshot.

2blackbar commented 2 years ago

So the conclusion is, its not an issue thats CFA related ? i think its something else, with wrong cfa we would see bayer grid. Heres dng pre conversion lg.zip Maybe ilia would be able to tell whats heppening when he comes back

MAybe its CFAPattern2 cause its different between these dngs , but simply changing it in exif wont solve it , i tried, kinda like changing matrix by exif didnt help, i had to force it in raw2mlv, maybe cfapattern2 should be passed as well but it isnt

masc4ii commented 2 years ago

Next I try to read the CFA from LibRAW and take this value into the MLV with raw2mlv. Who knows if we misinterpret something...

2blackbar commented 2 years ago

compiling raw2mlv and mlvapp on windows is pretty easy if yoyu would like to edit raw2mlv code and compile , you can run it on m1 with parallels, for mlvapp just qtcreator, for raw2mlv i made a guide in this zip so its pretty much automated, just dowmlopading mingw/msys2 Raw2MLVwinexe.zip

masc4ii commented 2 years ago
Bildschirmfoto 2021-12-23 um 08 13 05

What do you think about?! Some small changes in libMlv and raw2mlv. No new matrix. Unfortunately some of your dng's crash my new version (segmentation fault in memcpy) - no idea why. MLVApp doesn't need any change for this to display. This is the original lg.dng.

Bildschirmfoto 2021-12-23 um 08 17 55

That is frame-000006.dng.

Edit: by searching for the bug, I found that Ilia did the support in later version which aren't yet in MLVApp-raw2mlv build. He does what I wrote somewhere above: cut first row/column to make the file always start with the red pixel. But then, in doBinning() the app crashes exactly for these files, because they are smaller than expected.

2blackbar commented 2 years ago

wooq youre a magician!How i can do that? its fantastic , what do i have to change? So can you edit the code so it wont crash and ignore the size? This is huge cause i keep downloadingbdngs from other phones and a lot have gbrg and other orders of channels, so it limits my choicesvfor upgrade but now thatbit works, its great.

masc4ii commented 2 years ago

I could fix the crash. Will see if I can upload something later for you. On problem is still the camera matrix, which is not valid for all your dngs. It tells "MotionCam", but this is not the sensor, this is the app - and that is wrong. It must be the sensor name to find a valid matrix for it. E.g.: My phone takes dng photos. It is a BQ phone, but the dng tells "Samsung NX U". This one is listed in raw2mlv. Its CFA is GBRG. Pictures come out perfectly in MLVApp - also with camera matrix enabled. But I don't know yet, how to find the camera matrix without the raw2mlv list. The function in raw2mlv works fine for all Canon DSLR (I can read the exact same values from dng as in the matrices-list), but not for the phone dngs.

2blackbar commented 2 years ago

with some matrices i found theyre very similar, but white balancing is shifted and brightness/gamma , but if its rggb then most rggb matrices are similar.I uswd canon matrices on pixel and vice versa. yes i do rhink he should leave original camera id and ill talk to him about it. Use exif to change camera id , thats what i do when its problematic matrix , crude but works until i convince motioncam dev to not touch camera id. Can i apply your fixes to the code on my side so it would work? adding new matrices should be easy , theyre in dngs.

masc4ii commented 2 years ago

Try this: https://www.dropbox.com/s/r0g936lyu3gkqkf/LibMLV.zip?dl=0 It is a clone from last commit, before Ilia started the new development, with some very small changes.

2blackbar commented 2 years ago

Thanks a lot ! I copied code from c files , and itworks,! I have to flip the matrice like usual tho, i think it wont help if we just detect that its a DNG from LG v30, because this phone has both CFA's, maybe it needs something extra to detect that channels are flipped, on top of camera id. It has 3 cams, normal one has RGGB, wide and selfie have GBRG so these are flipped.

Wow, so many days, You did it , im super happy !

masc4ii commented 2 years ago

For my phone, MLVApp tells the phone name, but raw2mlv tells the sensor name and uses the matrix for it. I think this is correct, because matrices are for a sensor, not for the phone. For my phone, raw2mlv made a RGGB from GBRG, but the matrices are perfect with it, as I see in MLVApp. This is with camera matrix enabled.

Bildschirmfoto 2021-12-23 um 16 31 05

So I hope, if you get the correct sensor name and the correct matrices for it, it should look well.

2blackbar commented 2 years ago

OK ill inform the dev about it, this one are GRBG and they dont show up correctly, dngs are on bottom https://www.photographyblog.com/reviews/samsung_galaxy_s10_plus_review

masc4ii commented 2 years ago

OK ill inform the dev about it, this one are GRBG and they dont show up correctly, dngs are on bottom https://www.photographyblog.com/reviews/samsung_galaxy_s10_plus_review

Really? I think it's fine?!

Bildschirmfoto 2021-12-23 um 16 36 18 Bildschirmfoto 2021-12-23 um 16 58 34
2blackbar commented 2 years ago

Oh man i just forgot to copy new raw2mlv to mlvapp folder! They do work ! Sorry abouyt that ! Its all perfect now ! But i have one more that i cant even display properly with adobe dng codec! Try this one from xiaomi , can you even see these properly anywhere ? I cant https://drive.google.com/drive/folders/1vZ82LM1G-a3byj5VDfT3uX4CO1NrZXJR

On a sidenote, do you think these are true 8000x6000 or it 4000x3000 upscaled ?

masc4ii commented 2 years ago

But i have one more that i cant even display properly with adobe dng codec! Try this one from xiaomi , can you even see these properly anywhere ? I cant https://drive.google.com/drive/folders/1vZ82LM1G-a3byj5VDfT3uX4CO1NrZXJR

I'd say: works. For me it doesn't look upscaled. But you can see, that the resolution is a little high for the lenses - looks very soft.

Bildschirmfoto 2021-12-23 um 17 07 09
2blackbar commented 2 years ago

Great, i messaged motioncam dev and now im gonna look for my next phone that can keep up raw without stopping, for that i need at least 300 MB on 4k sensor, a lot of phones have slower internal memory writing speed than that. Theres app on playstore called crossplatform disk test, it has a chart for a lot of phones speed tests. Xiaomi mi 10 is very high at 444 MB ps , thats enough for 4k.Samsungs 21 dont work with motioncam for now. I love how the boats came out, it looks so much like film with reinhard tonemapping from mlvapp! Im really greateful for figuring this out , it was bugging me for a long time and i stuck to pixel cause it was the one i had working with mlvapp, but now, i can pick something that will deal with raw video.Amazing times !

It even works with hasselblad raws https://www.photographyblog.com/reviews/hasselblad_907x_50c_review

masc4ii commented 2 years ago

I have to say I am also impressed how good all these phone DNG files can look... and this using our tool. Seems I should use the DNG function more often. Thanks for telling about CPDT! Benchmark of my phone:

Now, I probably know, why it is not supported for RAW video... LOL

Would be cool, if motioncam fixes the camera matrix and camera id issues. Could become a really great tool!

2blackbar commented 2 years ago

Yes, and my pixel shows 100mb but i think its more like 40MB speed, so i can get barely 8 seconds of 4k in 16:9 It has pixel binning tho so we can get 2000x1500 and more frames. I did a lof of dng pics with my pixel but i see that a lot of phones looks imilar to it in mlvapp so im going to look for faster model. My lg v30 has speed of 150 and it records a bit longer but still cant deal with 4k 16:9 without stopping, it needs 300MB , well frames are aboyut 10mb, so 240mb is needed but id give it some headroom.

2blackbar commented 2 years ago

Oh i forgot about the 600-700 dngs limit in raw2mlv ,do you think this is related to command line limit or it ssomething inside raw2mlv ?

masc4ii commented 2 years ago

Hm... the longest clip I can find here has 937 frames and all were converted into MLV again from DNG. On macOS. No idea how many characters a windows command could have. But google tells me: "Windows (better, cmd.exe) has a command line length limit of 8192 characters." and "High Sierra (10.13.1) here, still 262144." Maybe someone should change the parameters from "type all frames independently" to "type first and last frame"...

2blackbar commented 2 years ago

How i can do that ? To type first and last frame ?

masc4ii commented 2 years ago

You'll have to change all the arguments interface of raw2mlv. Not that easy... Or maybe another idea: just input the folder and than raw2mlv scans all dng in right order... but also not easier to implement.

2blackbar commented 2 years ago

2nd option would be better

Not sure if you have that but when i import dngs converted to mlv then they have black point/level wrong, zeroed. so when i click repair and divide that by half , it gives real black point, it would be nice if it would be corrected someday in converter.

Can we compress dngs in raw2mlv ? i tried to set compress to 1 but it wont show up, the thing is that size of dngs is 5mb but after raw2mlv its 10 mb with 10 bits, and 14mb with 14 bits.

2blackbar commented 2 years ago

Just heads up - motioncam got card spanning, which means it can redord to internal and external SSD or SD card at the same time gaining a lot more recording time, i couldnt get 4k 16:9 over 10 seconds but now i recorded 40 seconds and could go on! Also hes considering MLV as export option for mac and windows tools !

masc4ii commented 2 years ago

Great news!

2blackbar commented 2 years ago

Its another news, he added compression so im getting 4k 16:9 and 24fps on pixel2, over 1 minute without stopping, it has about 140mb recording speed internally. I found 12k dng from smartphone, but its a tough one , i cant preview it anywhere with real colours. 125mb https://drive.google.com/file/d/1yCBdnnwshOVJSDj1GbYMxdTM2lao18wl/view?usp=sharing

masc4ii commented 2 years ago

Cool! Any way to support more devices? Would love to see my device there... ;)

This 12k file is very strange. Zoom in with "None" debayer in MLVApp: Bildschirmfoto 2022-01-04 um 15 42 28

This is RRGG RRGG GGBB GGBB or something like that... you see?

2blackbar commented 2 years ago

Exif , GRBG Also try motioncam, newest release from gitgub maybe it works already Yeah its a 108mp sensor from xiaomi mi10 Looks like some dual debayer

ExifTool Version Number : 12.37 File Name : 4_5956199661852167724.dng Directory : D:/RAW File Size : 125 MiB File Modification Date/Time : 2022:01:04 14:50:21+01:00 File Access Date/Time : 2022:01:04 14:55:38+01:00 File Creation Date/Time : 2022:01:04 14:55:38+01:00 File Permissions : -rw-rw-rw- File Type : DNG File Type Extension : dng MIME Type : image/x-adobe-dng Exif Byte Order : Little-endian (Intel, II) Make : google Camera Model Name : Mi 10 Preview Image Start : 157716 Orientation : Horizontal (normal) Rows Per Strip : 1486 Preview Image Length : 761516 Software : HDR+ 1.0.381773175nd Modify Date : 2021:11:25 07:52:04 Subfile Type : Full-resolution image Image Width : 12030 Image Height : 8920 Bits Per Sample : 16 Compression : JPEG Photometric Interpretation : Color Filter Array Samples Per Pixel : 1 Planar Configuration : Chunky Tile Width : 256 Tile Length : 256 Tile Offsets : (Binary data 15146 bytes, use -b option to ext ract) Tile Byte Counts : (Binary data 9967 bytes, use -b option to extr act) CFA Repeat Pattern Dim : 2 2 CFA Pattern 2 : 1 0 2 1 CFA Plane Color : Red,Green,Blue CFA Layout : Rectangular Black Level Repeat Dim : 2 2 Black Level : 1024 1024 1024 1024 White Level : 16368 Default Scale : 1 1 Default Crop Origin : 8 8 Default Crop Size : 12014 8904 Bayer Green Split : 500 Anti Alias Strength : 1 Best Quality Scale : 1 Active Area : 0 0 8920 12030 Opcode List 2 : GainMap, GainMap, GainMap, GainMap Opcode List 3 : WarpRectilinear Y Cb Cr Coefficients : 0.299 0.587 0.114 Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2) Y Cb Cr Positioning : Centered Reference Black White : 0 255 128 255 128 255 Exposure Time : 1/1212 F Number : 1.7 ISO : 50 Date/Time Original : 2021:11:25 07:52:04 Create Date : 2021:11:25 07:52:04 Shutter Speed Value : 1/1212 Aperture Value : 1.7 Brightness Value : 7.75680542 Exposure Compensation : 0 Max Aperture Value : 1.7 Subject Distance : 2.193 m Flash : Auto, Did not fire Focal Length : 6.7 mm Warning : [minor] Unrecognized MakerNotes Sub Sec Time : 831406 Sub Sec Time Original : 831406 Sub Sec Time Digitized : 831406 White Balance : Auto Digital Zoom Ratio : 0 Focal Length In 35mm Format : 24 mm Subject Distance Range : Close DNG Version : 1.4.0.0 DNG Backward Version : 1.3.0.0 Unique Camera Model : google Mi 10 Color Matrix 1 : 1.39 -0.7555 0.0554 -0.2302 1.0461 0.2132 0.01 0.0889 0.5099 Color Matrix 2 : 1.3274 -0.5957 -0.1337 -0.346 1.2159 0.1427 -0 .038 0.1561 0.487 Camera Calibration 2 : 1.0734 0 0 0 1 0 0 0 0.9871 Analog Balance : 1 1 1 As Shot Neutral : 0.549651 1 0.60413 Baseline Exposure : 0.84 Baseline Noise : 1 Baseline Sharpness : 1 Linear Response Limit : 1 Shadow Scale : 1 Maker Note Safety : Safe Calibration Illuminant 1 : Standard Light A Calibration Illuminant 2 : D65 Raw Data Unique ID : 9656A49E3B10FD618D36FE0CF71BB834 Camera Calibration Sig : com.adobe Profile Calibration Sig : com.adobe Profile Name : Kiari Standard Profile Hue Sat Map Dims : 90 30 1 Profile Hue Sat Map Data 1 : (large array of 8100 float values) Profile Hue Sat Map Data 2 : (large array of 8100 float values) Profile Embed Policy : Allow Copying Profile Copyright : Copyright 2019 Adobe Systems, Inc. Forward Matrix 1 : 0.3841 0.4695 0.1106 0.1605 0.8096 0.0298 0.05 81 0.0025 0.7645 Forward Matrix 2 : 0.3649 0.459 0.1404 0.1606 0.7987 0.0407 0.056 0.0035 0.7656 Profile Look Table Dims : 36 8 16 Profile Look Table Data : (large array of 13824 float values) Noise Profile : 1.53384626173647e-005 7.28708045016901e-008 1. 53384626173647e-005 7.28708045016901e-008 1.53384626173647e-005 7.28708045016901 e-008 New Raw Image Digest : 0d66ff71b2cf647e94eecb2a0f512a90 Aperture : 1.7 CFA Pattern : [Green,Red][Blue,Green] Image Size : 12030x8920 Megapixels : 107.3 Preview Image : (Binary data 761516 bytes, use -b option to ex tract) Scale Factor To 35 mm Equivalent: 3.6 Shutter Speed : 1/1212 Create Date : 2021:11:25 07:52:04.831406 Date/Time Original : 2021:11:25 07:52:04.831406 Modify Date : 2021:11:25 07:52:04.831406 Circle Of Confusion : 0.008 mm Depth Of Field : 5.83 m (1.30 - 7.13 m) Field Of View : 73.7 deg Focal Length : 6.7 mm (35 mm equivalent: 24.0 mm) Hyperfocal Distance : 3.16 m Light Value : 12.8 -- press ENTER --

masc4ii commented 2 years ago

It still tells "app is not compatible" when trying to install.

2blackbar commented 2 years ago

maybe android version is too old, i have 8

masc4ii commented 2 years ago

7.1.1 here. No update available.

2blackbar commented 2 years ago

Do You know how to fix this ones highlights ? It shows properly using adobe dng decoders https://drive.google.com/file/d/1NSFDs0787pWqRFX-bzEk3yCuou2Tor1m/view?usp=sharing in mlvapp its pinkblue , cant fix it The thing is, motioncam dev applies vignetting correction in new version using phone raw data info but after correction the highlights are destroyed in mlvapp, they look fine in other programs, Is this fixable in raw2mlv or in mlvapp ? My vignette had slightly greener corners and pinkish hue on black subjects that are in the middle, that correction is meant to fix it. Heres more dngs - https://drive.google.com/file/d/1qfO35fXfgAKnxo1khgvUYMrD1rFRBthM/view?usp=sharing

We talked about MLV for awhile yesterday and he said he would be able to record raw straight to MLV , but it would probably be without vignette correction using dng data, i think mlvapp is not using any sort of dng info to auto correct vignetting.

FIXED IT! I hope this wont break other dngs, had to change RawGetWhiteLevel(raw)))/2) 2 and pow to 3 ` / Round bitdepth up to a multiple of 2 */

define MAX(a,b) (((a)>(b))?(a):(b))

        source_bitdepth = (int)ceil(log2(MAX(RawGetMaxPixelValue(raw), RawGetWhiteLevel(raw)))/3) * 3;
        /* Set output bitdepth to be same as input if user has not specified anything */
        if (output_bits == 0) output_bits = source_bitdepth;                                                    
        shift_bits = source_bitdepth - output_bits;
        if (shift_bits < 0) shift_bits = -shift_bits;
        float lscale = pow(3.0, output_bits - source_bitdepth);`
masc4ii commented 2 years ago

Can you tell more about how you fixed that? What file, what line, what...? I checked the RAW data in MLVApp and all those wrong colored pixels come in with value 0 - so MLVApp should show the truth. --> Ah okay... found it. Will have a look and will try to understand the code... --> Your code change doesn't work for me. I get a black frame with that.

MLVApp can't autocorrect vignettes. But I build the vignette correction, where it shouldn't be to hard to correct manually. Can't tell, how it is realized in DNGs.

masc4ii commented 2 years ago

Okay... found the problem. I read this from the DNG: RawGetMaxPixelValue(raw): 16384, RawGetWhiteLevel(raw): 16384, output_bits: 14 2^14 = 16384. So valid range is 0..16383. White level and highest value is 1 too high.

The picture is shown correct if you set shift_bits = -1. So you devide all picture data by 2 and the 16384 becomes 8196, which then is in 14bit range. But you loose half of bitdepth. Kind of hack... It would be better, if the picture data is in valid range.

2blackbar commented 2 years ago

Well from what ive seen 14 bits and 12 or 10 they dont differe that much in mlvapp cause probably canons all shoot 14bit and lower bit dngs like 12 and 10 are derived from that so even if thrers color loss its still more colors than capuiring straight to 10 bits, cause 10 bits from phone doesnt have as many colors like 10 bits from canon at least for my experiments, but its close, some phones do have it but probably capture at more bits its still something id have to test, exiftool always says 16 bits so thats no use.Anyway heres my c file contents , i just changed pow to 3 like i wrote above, this is needed cause with official raw2mlv the one that comes with mlvapp you cant open some dngs from phones and whitelevel is too high which results in magenta skies that arent fixable: raw2mlv.zip

By the way we have discord for motioncam, it can do RAW 4k,,6k and 8k24fps on some phones : https://discord.gg/3hrDBPNN `#include

include

include

include "../LibMLV/LibMLV.h"

/ LibRaw wrapper /

include "read_raw.c"

/ Camera matrix data /

include "camera_matrices.c"

void print_help() { puts( "Arguments:\n" " -h, --help Print help\n" " -o Output file name\n" " -b, --bitdepth Output bitdepth, 8 to 16, even numbers\n" // " --compression <0/1> Output compression, 0=none, 1=LJ92\n" " -f, --framerate Framerate as a fraction, ex: -f 24000 1001\n" // " --crop Crop\n" "Example:\n" " ./raw2mlv pic1.raw pic2.raw pic3.raw -o myvid.mlv --bitdepth 12\n"); }

int main(int argc, char * argv) { / Output parameters / char output_name = "output.mlv"; int num_input_files = 0; char * input_files = malloc(argc sizeof(char *)); int output_bits = 14; int output_compression = 0; int width = 0; int height = 0; int output_fps_top = 24000; int output_fps_bottom = 1001;

/* Source data info */
int source_bitdepth = 14; /* Will be figured out later */
int shift_bits = 0; /* How many bits to shift to get to output bitdepth */

/* Count how many frames have been written */
int written_frames = 0;

/* Parse arguments */
for (int i = 1; i < argc; ++i)
{
    if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
        print_help();
        exit(0);
    } else if (!strcmp(argv[i], "-b")) {
        output_bits = atoi(argv[i+1]);
        printf("Bitdepth set to %i\n", output_bits);
        if ((output_bits % 2) != 0 || output_bits>16 || output_bits<10) {
            puts("Unsupported bitdepth, choose 10/12/14/16.");
            exit(1);
        }
        ++i;
    } else if (!strcmp(argv[i], "-o")) {
        output_name = argv[i+1];
        printf("Output name set to %s\n", output_name);
        ++i;
    } else if (!strcmp(argv[i], "--compression")) {
        output_compression = atoi(argv[i+1]);
        char * compression = (output_compression) ? "none" : "LJ92";
        printf("Compression set to %i (none)\n", output_compression);
        ++i;
    } else if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--framerate")) {
        output_fps_top = atoi(argv[i+1]);
        output_fps_bottom = atoi(argv[i+2]);
        printf("FPS set to %.3f\n",(float)output_fps_top/output_fps_bottom);
        i += 2;
    } else {
        input_files[num_input_files++] = argv[i];
    }
}

/****************************** MLV creation ******************************/

/* Allocate memory for the mlv writer object */
MLVWriter_t * writer = malloc(sizeof_MLVWriter());

/* Open file and create pointer for packed frame data */
FILE * mlv_file = fopen(output_name, "wb");
uint8_t * packed_frame_data = NULL;

/* Write each frame */
for (int f = 0; f < num_input_files; ++f)
{
    /* Open raw file with RawReader (wrapper for LibRaw) */
    RawReader_t raw[1];
    if (init_RawReader(raw, input_files[f]) != 0)
        printf("Can't read file %s\n", input_files[f]);

    /* Initialise MLV writer and write MLV headers when it's first frame */
    if (f == 0)
    {
        /* Round bitdepth up to a multiple of 2 */
        source_bitdepth = (int)ceil(log2(RawGetWhiteLevel(raw))/2) * 2;
        shift_bits = source_bitdepth - output_bits;
        if (shift_bits < 0) shift_bits = -shift_bits;
        float lscale = pow(2.0, output_bits - source_bitdepth);

        printf("Detected source bitdepth: %i\n", source_bitdepth);

        /*************************** Set values ***************************/

        width = RawGetWidth(raw);
        height = RawGetHeight(raw);

        packed_frame_data = malloc((width * height * output_bits) / 8);

        /********************* Initialise MLV writer **********************/

        /* Set basic image parameters */
        init_MLVWriter( writer,
                        width, /* Width */
                        height, /* Height */
                        output_bits, /* Bitdepth */
                        output_compression, /* Compressed LJ92? */
                        RawGetBlackLevel(raw)*lscale, /* Black level */
                        RawGetWhiteLevel(raw)*lscale, /* White level */
                        output_fps_top, /* FPS fraction */
                        output_fps_bottom );

        /*********************** Set camera info... ***********************/

        /* Try to look up adobe matrix */
        CameraMatrixInfo_t * mat = FindCameraMatrixInfo(RawGetCamName(raw));
        double * camera_matrix = NULL;

        /* If no matrix found from adobe, use libraw one (most likely the same) */
        if (mat != NULL)
            camera_matrix = mat->ColorMatrix2;
        else
            camera_matrix = RawGetMatrix(raw);

        MLVWriterSetCameraInfo( writer,
                                RawGetCamName(raw), /* Camera name string */
                                0, /* Model ID, only useful for ML cams */
                                camera_matrix /* Daylight camera matrix */);

        /************** Leave blank space in file for headers *************/

        fseek(mlv_file, MLVWriterGetHeaderSize(writer), SEEK_SET);
    }
    else
    {
        /* Make sure everything is right */
        if ( RawGetWidth(raw) != width
         || RawGetHeight(raw) != height)
        {
            printf("File %s has different resolution!\n", input_files[f]);
        }
    }

    /* Calculate frame size, TODO: compressed frames will be different */
    size_t frame_size = (width * height * output_bits) / 8;

    /*************************** Write the frame **************************/

    /* Get frame header size, telling MLVWriter how big the frame is */
    size_t frame_header_size = MLVWriterGetFrameHeaderSize(writer);

    /* Create memory for frame header */
    void * frame_header_data = malloc(frame_header_size);

    /* Get frame header */
    MLVWriterGetFrameHeaderData(writer,f,frame_size,frame_header_data);

    /* Write it */
    fwrite(frame_header_data, frame_header_size, 1, mlv_file);

    free(frame_header_data);

    /* Now write actual frame data */
    uint16_t * bayerimage = RawGetImageData(raw);

    if (output_bits < source_bitdepth)
        for (int i = 0; i < width*height; ++i) bayerimage[i] >>= shift_bits;
    else
        for (int i = 0; i < width*height; ++i) bayerimage[i] <<= shift_bits;

    if (output_bits == 16)
        packed_frame_data = (void *)bayerimage;
    else if (output_bits == 14)
        MLVPackFrame14(bayerimage, width*height, packed_frame_data);
    else if (output_bits == 12)
        MLVPackFrame12(bayerimage, width*height, packed_frame_data);
    else if (output_bits == 10)
        MLVPackFrame10(bayerimage, width*height, packed_frame_data);

    fwrite(packed_frame_data, frame_size, 1, mlv_file);

    written_frames++;

    uninit_RawReader(raw);
}

/***************************** Write headers ******************************/

/* Now go back to the start of the file */
fseek(mlv_file, 0, SEEK_SET);

/* Allocate array for header data */
size_t header_size = MLVWriterGetHeaderSize(writer);
void * header_data = malloc(header_size);

/* Get header data */
MLVWriterGetHeaderData(writer, header_data, written_frames);

/* Write header data to the file */
fwrite(header_data, header_size, 1, mlv_file);

free(header_data);

/********************************** DONE **********************************/

if (packed_frame_data != NULL) free(packed_frame_data);
fclose(mlv_file);
uninit_MLVWriter(writer);
free(writer);
free(input_files);

return 0;

} `