How do I calculate FPS from data in a .mov file? - file

I've been writing a program in C# that reads a .mov file. I'm able to parse through the entire thing, ignoring chunks I don't understand, and grabbing relevant info from chunks that I do.
What I'm trying to do is get the FPS from the file, but getting it hasn't been straightforward. I assume because the format can store many movies at different rates.
If someone could point me in the right direction, like which chunks (atoms) should I be looking at? I thought it was stts, but not all .mov files contain that chunk!

I was mistaken. The stts atom is always there, and that is where you get the information to calculate the FPS. The following code hasn't be thoroughly tested, but it did work with all the .mov files I have.
void ReadSTTS(BinaryReader reader)
{
int versionAndFlags = reader.ReadInt32(true);
int nEntries = reader.ReadInt32(true);
int sampleCount = 0;
int sampleDuration = 0;
for (int i = 0; i < nEntries; i++)
{
sampleCount += reader.ReadInt32(true);
sampleDuration += reader.ReadInt32(true);
}
FPS = (float)Math.Round((float)mediaTimeScale / ((float)mediaDuration / (float)sampleCount), 2);
}
mediaTimeScale and mediaDuration both come from the mvhd atom. ReadInt32(true) is an extension that changes the endianness, since I'm reading the .mov on a windows machine.

Related

OpenCV Tiff Wrong Color Values Readout

I have a 16-bit tiff image with no color profile (camera profile embedded) and I am trying to read its RGB values in OpenCV. However, comparing the output values to the values given when the image is opened by GIMP for example gives totally different values (GIMP being opened with keeping the image's profile option; no profile conversion). I have tried also another image studio software like CaptureOne and the result accords with GIMP differs from OpenCV output.
Not sure if reading and opening the image in OpenCV is wrong somehow, in spite of using IMREAD_UNCHANGED flag.
I have as well tried to read the image using FreeImage library but still the same result.
Here is a snippet of the code reading pixels' values in OpenCV
const float Conv16_8 = 255.f / 65535.f;
cv::Vec3d curVal;
// upperLeft/lowerRight are just some pre-defined corners for the ROI
for (int row = upperLeft.y; row <= lowerRight.y; row++) {
unsigned char* dataUCPtr = img.data + row * img.step[0];
unsigned short* dataUSPtr = (unsigned short*)dataUCPtr;
dataUCPtr += 3 * upperLeft.x;
dataUSPtr += 3 * upperLeft.x;
for (int col = upperLeft.x; col <= lowerRight.x; col++) {
if (/* some check if the pixel is valid */) {
if (img.depth() == CV_8U) {
for (int chan = 0; chan < 3; chan++) {
curVal[chan] = *dataUCPtr++;
}
}
else if (img.depth() == CV_16U) {
for (int chan = 0; chan < 3; chan++) {
curVal[chan] = (*dataUSPtr++)*Conv16_8;
}
}
avgX += curVal;
}
else {
dataUCPtr += 3;
dataUSPtr += 3;
}
}
}
and here is the image (download the image) I am reading with its RGB readouts in
CaptureOne Studio AdobeRGB:
vs OpenCV RGB (A1=white --> F1=Black):
PS1: I have tried also to change the output color space in GIMP/CaptureOne to sRGB but still the difference is almost the same, not any closer to OpenCV
PS2: I am reversing OpenCV imread channels' order before extracting the RGB values from the image COLOR_RGB2BGR
OP said:
I have a 16-bit tiff image with no color profile (camera profile embedded)
Well no, your image definitely has a color profile, and it should not be ignored. The embedded profile is as important as the numeric values of each pixel. Without a defined profile, the pixel values are somewhat meaningless.
From what I can tell, OpenCV does not linearize gamma by default... except when it does... Regardless, the gamma indicated in the profile is unique:
Now compare that to sRGB:
So the sRGB transformations can't be used.
If you are looking for performance, applying the curve via LUT is usually more efficient than a full-on color management system.
In this case, using a LUT. The following LUT was taken from the color profile, 16bit values, and 256 steps:
// Phase One TRC from color profile
profileTRC = [0x0000,0x032A,0x0653,0x097A,0x0CA0,0x0FC2,0x12DF,0x15F8,0x190C,0x1C19,0x1F1E,0x221C,0x2510,0x27FB,0x2ADB,0x2DB0,0x3079,0x3334,0x35E2,0x3882,0x3B11,0x3D91,0x4000,0x425D,0x44A8,0x46E3,0x490C,0x4B26,0x4D2F,0x4F29,0x5113,0x52EF,0x54BC,0x567B,0x582D,0x59D1,0x5B68,0x5CF3,0x5E71,0x5FE3,0x614A,0x62A6,0x63F7,0x653E,0x667B,0x67AE,0x68D8,0x69F9,0x6B12,0x6C23,0x6D2C,0x6E2D,0x6F28,0x701C,0x710A,0x71F2,0x72D4,0x73B2,0x748B,0x755F,0x762F,0x76FC,0x77C6,0x788D,0x7951,0x7A13,0x7AD4,0x7B93,0x7C51,0x7D0F,0x7DCC,0x7E8A,0x7F48,0x8007,0x80C8,0x8189,0x824C,0x8310,0x83D5,0x849B,0x8562,0x862B,0x86F4,0x87BF,0x888A,0x8956,0x8A23,0x8AF2,0x8BC0,0x8C90,0x8D61,0x8E32,0x8F04,0x8FD7,0x90AA,0x917E,0x9252,0x9328,0x93FD,0x94D3,0x95AA,0x9681,0x9758,0x9830,0x9908,0x99E1,0x9ABA,0x9B93,0x9C6C,0x9D45,0x9E1F,0x9EF9,0x9FD3,0xA0AD,0xA187,0xA260,0xA33A,0xA414,0xA4EE,0xA5C8,0xA6A1,0xA77B,0xA854,0xA92D,0xAA05,0xAADD,0xABB5,0xAC8D,0xAD64,0xAE3B,0xAF11,0xAFE7,0xB0BC,0xB191,0xB265,0xB339,0xB40C,0xB4DE,0xB5B0,0xB680,0xB750,0xB820,0xB8EE,0xB9BC,0xBA88,0xBB54,0xBC1F,0xBCE9,0xBDB1,0xBE79,0xBF40,0xC005,0xC0CA,0xC18D,0xC24F,0xC310,0xC3D0,0xC48F,0xC54D,0xC609,0xC6C5,0xC780,0xC839,0xC8F2,0xC9A9,0xCA60,0xCB16,0xCBCA,0xCC7E,0xCD31,0xCDE2,0xCE93,0xCF43,0xCFF2,0xD0A0,0xD14D,0xD1FA,0xD2A5,0xD350,0xD3FA,0xD4A3,0xD54B,0xD5F2,0xD699,0xD73E,0xD7E3,0xD887,0xD92B,0xD9CE,0xDA6F,0xDB11,0xDBB1,0xDC51,0xDCF0,0xDD8F,0xDE2C,0xDEC9,0xDF66,0xE002,0xE09D,0xE138,0xE1D2,0xE26B,0xE304,0xE39C,0xE434,0xE4CB,0xE562,0xE5F8,0xE68D,0xE722,0xE7B7,0xE84B,0xE8DF,0xE972,0xEA04,0xEA97,0xEB29,0xEBBA,0xEC4B,0xECDC,0xED6C,0xEDFC,0xEE8B,0xEF1A,0xEFA9,0xF038,0xF0C6,0xF154,0xF1E1,0xF26F,0xF2FC,0xF388,0xF415,0xF4A1,0xF52D,0xF5B9,0xF645,0xF6D0,0xF75B,0xF7E6,0xF871,0xF8FC,0xF987,0xFA11,0xFA9B,0xFB26,0xFBB0,0xFC3A,0xFCC4,0xFD4E,0xFDD7,0xFE61,0xFEEB,0xFF75,0xFFFF]
If a matching array of the linearized values was needed, it would be
[0x0000,0x0101,0x0202,0x0303,0x0404....
But such an array is not neded for most uses, as the index value of the PhaseOne TRC array directly relates to the linear value.
I.e. phaseOneTRC[0x80] is 0xAD64
and the linear value is 0x80 * 0x101.
It turned out, it is all about having, loading and applying the proper ICC profile on the cv::Mat data. To do that one must use a color management engine along side OpenCV such as LittleCMS.

Extracting data from an unknown encoding file

We use testing equipment (1995 year manufacturing) powered by MS DOS. Analog-digital converter records information in the file.
In [picture1] is shown the structure of that file.
In [picture2] is shown the oscillogram that constructed according to the data from the file (program for opening the file on MS DOS).
Below I placed link to this file (google drive).
This file contains the data that need for me - the massive of point of oscillogram. I want have opportunities to keep, analyze and print this chart on Windows or Linux (not MS DOS). So I need to extract data from the file.
But I can't make it. And no program (known to me) can't open this file. I analyzed a few first byte and they point to program 'TRAS v4.99'. This program is on MS DOS.
But I really hope, that it is really to get data without this program.
P.S. If anyone will say it is impossible - it is will well too because I haven't found point of view yet:)
Thank you for your time! Best regards!
LINK TO FILE ON GOOGLE DISK - 00014380.K00
STRUCTURE OF FILE
OPENING FILE VIA PROGRAM IN MS DOS
Here is an idea on how you can tackle this problem. Since the format is relatively well specified in the handbook you can use the Java programming language for example with something like java.io.RandomAccessFile to read arrays of bytes. These arrays of bytes can then be converted to Java primitive types OR to string according to the data type. After this conversion you can the print out the data in a human readable format.
Below you can find some sample code to give you an idea of what you could do with this approach (I have not tested the code, it is not complete, it is just to give you an idea of what you can do):
public static void readBinaryfile() throws IOException {
java.io.RandomAccessFile randomAccessFile = new RandomAccessFile("test.bin", "r");
byte[] addKenStrBytes = new byte[12];
randomAccessFile.read(addKenStrBytes);
String addKenStr = new String(addKenStrBytes, "UTF-8");
// TODO: Do something with addKenStr.
System.out.println(addKenStr);
byte[] kopfSizeBytes = new byte[2];
randomAccessFile.read(kopfSizeBytes);
// TODO: Do something with kopfSizeBytes
System.out.println(convertToInt(kopfSizeBytes));
byte[] addRufNrCounterBytes = new byte[6];
randomAccessFile.read(addRufNrCounterBytes);
long addRufNrCounter = convertToLong(addRufNrCounterBytes);
// TODO: Do something with addRufNrCounter
System.out.println(addRufNrCounter);
byte[] endAdrBytes = new byte[4];
randomAccessFile.read(endAdrBytes);
// TODO: Do something with endAdrBytes
System.out.println(convertToLong(endAdrBytes));
// Continue here and after you reached the end of the record repeat until you reached the end off the file
}
private static int convertToInt(byte[] bytes) {
if(bytes.length > 4) {
throw new IllegalArgumentException();
}
int buffer = 0;
for(byte b : bytes) {
buffer |= b;
buffer = buffer << 8;
}
return buffer;
}
private static long convertToLong(byte[] bytes) {
if(bytes.length > 8) {
throw new IllegalArgumentException();
}
long buffer = 0L;
for(byte b : bytes) {
buffer |= b;
buffer = buffer << 8;
}
return buffer;
}
Note that fields with more than 8 bytes need to be most probably converted to strings. This is not complete code, just an example to give you an idea on how you can tackle this problem.

How to get a string representation of an audio AVStream in ffmpeg?

I'm using ffmpeg. Consider the following piece of code:
for(i=0; i<pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO) {
//how do I get the language of the stream?
}
}
I found out that there is a LangEntry struct in libavformat (avlanguage file), there's also a table containing languages and their codes, seems it's just what I need. But I don't know how to use it. I couldn't find any examples of its usage. There are no reference to the LangEntry neither in AVStream, nor in AVCodecContext.
The LangEntry has nothing to do with your objective of detecting the language.
In fact, LangEntry table is to do with List of ISO 639-2 codes
Language code gets encoded as metadata, so you should be trying as below to identify the language
AVDictionaryEntry *lang;
for(i=0; i<pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)
{
lang = av_dict_get(pFormatCtx->streams[i]->metadata, "language", NULL,0);
// Check lang->value, it should give 3-letter word matching to one of the LangEntry Table
}
}

libqrencode produces qr codes that some android/ios readers cannot read

I'm developing an embedded application where a device generates QR codes on an LCD screen.
the code generation part seems to work just fine, but I seem to have some trouble with decoding it.
I generate the QR code via the function
QRcode *qr = QRcode_encodeString8bit("http://some/url/", 0, QR_ECLEVEL_Q);
then convert it to a format that can be read by the image library to be displayed on the screen. However, while the "QR Droid" app on Android can read it and send me to the URL just fine, another one called "Qr Barcode Scanner" doesn't seem to recognize the code, even though it seems to detect the alignment points. Same goes for iOS - some apps read it fine and some apps just act like it's not a code.
What could be the possible cause of this problem? I tried different error correction levels and that's not it.
Thanks in advance for your replies..
Edit: Apparently the code was flipped horizontally. I changed how I convert it to a 16-bit image, and it worked. I'm putting down a code snippet for future reference, in case someone else stumbles upon the same issue.
QRcode *qr = QRcode_encodeString8bit(string, 0, QR_ECLEVEL_H);
int i, j;
for (i = 0; i < qr->width; i++) {
for (j = qr->width - 1; j >= 0; j--) { //flipped this
if (qr->data[(j * qr->width) + i] & 0x1)
*(qr_img++) = COLOR_16BIT_BLACK;
else
*(qr_img++) = COLOR_16BIT_WHITE;
}
}
In my case the code that works( compare with a qr code generator which outputs the same resoult) looks like this
QRcode *qr;
qr = QRcode_encodeString("ABC012345", 0, QR_ECLEVEL_H, QR_MODE_8, 1);
int i_qr, j_qr;
for (i_qr = 0; i_qr < qr->width; i_qr++) {
for (j_qr = 0; j_qr < qr->width; j_qr++) {
if (qr->data[(i_qr * qr->width) + j_qr] & 0x1)
printf("*");
else
printf(" ");
}
printf("\n");
}
#smparkes I'm not sure the QR code is flipped. zxing reads it OK, and it does not allow mirrored codes (not without TRY_HARDER).
Yes, mirror images of valid QR codes are never valid; rotations are. I suppose I would be surprised if the library just generates invalid QR codes all the time. QR Droid is just based on zxing too, so would be surprised if it goes out of its way to also read these invalid codes.
But then again the other bits of evidence suggest mirroring is the issue.

Trying to write a video file using OpenCV

I’m trying to use OpenCV to write a video file. I have a simple program that loads frames from a video file then accepts to save them
At first the cvCreateVideoWrite always return NULL. I got a answer from your group saying it returns separate images and to try to change the file name to test0001.png, this worked.
But now the cvWriteFrame function always fails, the code is
CString path;
path="d:\\mice\\Test_Day26_2.avi";
CvCapture* capture = cvCaptureFromAVI(path);
IplImage* img = 0;
CvVideoWriter *writer = 0;
int isColor = 1;
int fps = 25; // or 30
int frameW = 640; // 744 for firewire cameras
int frameH = 480; // 480 for firewire cameras
writer=cvCreateVideoWriter("d:\\mice\\test0001.png",CV_FOURCC('P','I','M','1'),
fps,cvSize(frameW,frameH),isColor);
if (writer==0)
MessageBox("could not open writter");
int nFrames = 50;
for(int i=0;i<nFrames;i++){
if (!cvGrabFrame(capture))
MessageBox("could not grab frame");
img=cvRetrieveFrame(capture); // retrieve the captured frame
if (img==0)
MessageBox("could not retrive data");
if (!cvWriteFrame(writer,img) )
MessageBox("could not write frame");
}
cvReleaseVideoWriter(&writer);
Try CV_FOURCC('D', 'I', 'V', 'X'), CV_FOURCC('f', 'f', 'd', 's') (with *.avi filename) or CV_FOURCC_DEFAULT (with *.mpg). Video writing is still quite messy in opencv >_>
I've seen many issues with writing video as well in OpenCV. I found intel iYUV format worked well for what I needed.
Was your library built with HAVE_FFMPEG defined?
If it wasn't,you might need to recompile opencv with that option.You should see something like this in the configure step:
...
Video I/O--------------
Use QuickTime no
Use xine no
Use ffmpeg: yes
Use v4l yes
...
If you don't have ffmpeg,you can get it from here.

Resources