I'm learning to use the H.264 encoder in Windows Media Foundation.
What I currently have are media samples in YUV420p format, so that's buffers containing YYYYYYYYUUVV data.
Since the H.264 encoder MFT requires input in form of IMFSample, I'm not sure how to convert the data in buffer into IMFSample.
May I just do like this:
IMFMediaBuffer *pBuffer = NULL;
MFCreateMemoryBuffer(cbSize, &pBuffer);
BYTE *pData = NULL;
pBuffer->Lock(&pData, NULL, NULL);
memcpy(pData, bufferIhaveinYYYYUV format, buffer size); // is it correct?
pBuffer->Unlock();
IMFSample *pSample = NULL;
MFCreateSample(&pSample);
pSample->AddBuffer(pBuffer);
Thanks
This is how I do it (full example at https://github.com/sipsorcery/mediafoundationsamples/blob/master/MFMP4ToYUVWithMFT/MFMP4ToYUVWithMFT.cpp):
IMFMediaBuffer *srcBuf = NULL;
DWORD srcBufLength;
byte *srcByteBuffer;
DWORD srcBuffCurrLen = 0;
DWORD srcBuffMaxLen = 0;
CHECK_HR(videoSample->ConvertToContiguousBuffer(&srcBuf), "ConvertToContiguousBuffer failed.\n");
CHECK_HR(srcBuf->GetCurrentLength(&srcBufLength), "Get buffer length failed.\n");
CHECK_HR(srcBuf->Lock(&srcByteBuffer, &srcBuffMaxLen, &srcBuffCurrLen), "Error locking source buffer.\n");
//// Now re-constuct.
MFCreateSample(&reConstructedVideoSample);
CHECK_HR(MFCreateMemoryBuffer(srcBufLength, &reConstructedBuffer), "Failed to create memory buffer.\n");
CHECK_HR(reConstructedVideoSample->AddBuffer(reConstructedBuffer), "Failed to add buffer to re-constructed sample.\n");
CHECK_HR(reConstructedVideoSample->SetSampleTime(llVideoTimeStamp), "Error setting the recon video sample time.\n");
CHECK_HR(reConstructedVideoSample->SetSampleDuration(llSampleDuration), "Error setting recon video sample duration.\n");
byte *reconByteBuffer;
DWORD reconBuffCurrLen = 0;
DWORD reconBuffMaxLen = 0;
CHECK_HR(reConstructedBuffer->Lock(&reconByteBuffer, &reconBuffMaxLen, &reconBuffCurrLen), "Error locking recon buffer.\n");
memcpy(reconByteBuffer, srcByteBuffer, srcBuffCurrLen);
CHECK_HR(reConstructedBuffer->Unlock(), "Error unlocking recon buffer.\n");
reConstructedBuffer->SetCurrentLength(srcBuffCurrLen);
Related
I'm constantly sending structs of int64 via Pyserial with:
with serial.Serial(port='COM4', baudrate=115200, timeout=.1) as arduino:
value = write_read(struct.pack(">q", int_array[1][i])) #this sends signed int.64 in bytes
print(value)
the struct.pack has this shape, for example:
b'\xff\xff\xff\xff\xff\xff\xff\xef'
and the function write_read consists of:
def write_read(x):
arduino.write((x))
data = arduino.readline()
#the idea is to receive an ACK from the Arduino after 8 bytes (the full
#number)
return data
The code I'm trying to develop in arduino is the following:
void loop() {
// send data only when you receive data:
if (Serial.available() \> 0) {
// read the incoming byte:
incomingByte = Serial.read();
//read 8 bytes and create the result
r= function_to_read_8_last_bytes // or similar
// say what you got:
Serial.print("I received: ");
Serial.printlesultn(r, DEC);
Serial.write("ACK");
}
}
I'm very curious how I could do a robust "read 8 bytes" function.
Should I add some especial character in the Python part to indentify when it ends one value?
Thanks! I'll appreciate any help :)
Given the discussion in the comments, it's hard to receive a stream of bytes and be sure that the receiver is completely synchronized. However let's make some assumptions to ease the problem:
The serial buffer is empty when you connect your laptop to Arduino. This ensures you won't receive spurious data with no meaning. I had this problem happens a lot when the serial connection was ended abruptly by any cause.
You are not constantly sending bytes, Arduino has time to process them until the start of the new sequence.
You only send this data, so there is no need to create a higher level protocol on top of it. Bare in mind that the serial communication is almost just an hardware stack, you receive bytes with no headers.
For assumption 1 you can write a simple piece of code to consume all the spurious bytes in the serial buffer as soon as your main starts from Arudino, so this will be done everytime you connect the serial (as this is also where the power supply comes from). Something like this:
void serialFlush(){
while(Serial.available() > 0) {
char t = Serial.read();
}
}
You can send a "READY" signal back to the Python interface, so that the program knows you are ready to receive data.
Going on with the solution you can implement an easy CRC in python, an additional byte which contains a XOR of all the previous bytes, and you check that in Arduino upon reception complete.
def xor_reduce_long_int(li):
res = 0;
for i in range(8):
mask = (0xFF)<<(i*8)
print(hex(mask))
masked = (li&mask)>>(i*8)
res ^= masked
return res
with serial.Serial(port='COM4', baudrate=115200, timeout=.1) as arduino:
crc=xor_reduce_long_int(int_array[1][i])
value = write_read(struct.pack(">qc", int_array[1][i],crc)) #this sends signed int.64 in bytes
print(value)
And with Arduino I would read 8 bytes when they are available and put them into an unsigned char buffer. I would then define a union that alias such buffer to interpret it as long long int.
typedef struct long_int_CRC
{
union
{
unsigned char bytes[8];
long int data;
};
unsigned char CRC;
}data_T;
// .. Later in main
data_T = received_data;
int received_bytes=0
unsigned char my_CRC = 0;
unsigned char rec_byte= 0;
while( received_bytes < 8 )
{
if(Serial.available() )
{
// Get the byte
rec_byte = Serial.read()
// Store the byte and calc CRC
received_data.bytes[received_bytes] = rec_byte;
my_CRC ^= rec_byte;
// Increment counter for next byte
received_bytes++;
}
}
// Reception complete, check CRC
unsigned char rec_CRC;
if(Serial.available() )
{
rec_CRC = Serial.read()
}
if( my_CRC != rec_CRC )
{
// Something was wrong!
}
// Now access your data as a long int
Serial.print("I received: ");
Serial.printlesultn(received_data.data, DEC);
Serial.write("ACK");
I am currently trying to communicate with an absolute encoder over serial, and as you can see from the picture below, it is responding fine to my requests, but the problem I am having is arduino is not reading the response bytes correctly all the time. The request from the encoder for position is the command 0x64 which responds with 4 bytes which consist of an echo byte (0x64 in picture), two bytes of data (0xAD and 0x53 in picture), and a error byte (0x00 in picture). What I am currently doing is sending the command, reading 4 bytes and as a way of debugging I am writing the response of the echo byte back to the serial port (0x18 in picture). As you can see 0x18 != 0x64 so I'm wondering where I am going wrong. I have double checked the baudrate and I'm talking at the correct speed, I just cannot seem to get a consistent read on the response. Below is a simplified version of the code that I have been running to try and fix this issue. The delayMicroseconds() is just there to separate the bytes on the oscilloscope.
Serial.write(0x64);
byte echo_byte = 0;
byte pos_1 = 0;
byte pos_2 = 0;
byte status_byte = 0;
echo_byte = Serial.read();
pos_1 = Serial.read();
pos_2 = Serial.read();
status_byte = Serial.read();
delayMicroseconds(1000);
Serial.write(echo_byte)
You must check and wait until there is a byte available to read on the port before calling Serial.read(). If there are no bytes available for reading, Serial.read() returns -1.
as in:
byte echo_byte = 0;
byte pos_1 = 0;
byte pos_2 = 0;
byte status_byte = 0;
Serial.write(0x64);
while (Serial.available() < 4) // wait for the 4 byte message.
;
Serial.read(echo_byte);
Serial.read(pos_1);
Serial.read(pos_2);
Serial.read(status_byte);
This is a bit cumbersome, and prone to errors, so Serial.readBytes is usually used for mylti-byte transfers, as in:
// Reads position from encoder, returns true if pos is valid.
bool read_pos(unsigned short& pos)
{
struct pos_msg
{
byte echo_byte;
unsigned short pos;
byte status;
};
Serial.write(0x64);
pos_msg msg;
Serial.readBytes((char*)&msg, sizeof(msg));
if (msg.echo_byte != 0x64 || msg.status != 0)
return false;
pos = msg.pos;
return true;
}
There is following code:
QFile in("c:\\test\\pic.bmp");
in.open(QFile::ReadOnly);
QByteArray imageBytes = in.readAll();
socket->write(bytesToSend);
On server, i'm receiving only header of .bmp file. What could cause such behavior? And How to solve this problem?
This method writes at most number of bytes which is your data size. But can actually write less. It actually returns number of bytes sent. So you should make a loop sending the rest of data until everything is sent. Like this.
qint64 dataSent = 0;
while(dataSent < sizeof(bytesToSend))
{
qint64 sentNow = socket->write(bytesToSend+dataSent);
if(sentNow >= 0)
dataSent += sentNow;
else
throw new Exception();
}
This is a native socket behavior.
I'm decompressing gzip data received from a http server, using the zlib library from Qt. Because qUncompress was no good, I followed the advice given here: Qt quncompress gzip data and created my own method to uncompress the gzip data, like this:
QByteArray gzipDecompress( QByteArray compressData )
{
//strip header
compressData.remove(0, 10);
const int buffer_size = 16384;
quint8 buffer[buffer_size];
z_stream cmpr_stream;
cmpr_stream.next_in = (unsigned char *)compressData.data();
cmpr_stream.avail_in = compressData.size();
cmpr_stream.total_in = 0;
cmpr_stream.next_out = buffer;
cmpr_stream.avail_out = buffer_size;
cmpr_stream.total_out = 0;
cmpr_stream.zalloc = Z_NULL;
cmpr_stream.zfree = Z_NULL;
cmpr_stream.opaque = Z_NULL;
int status = inflateInit2( &cmpr_stream, -8 );
if (status != Z_OK) {
qDebug() << "cmpr_stream error!";
}
QByteArray uncompressed;
do {
cmpr_stream.next_out = buffer;
cmpr_stream.avail_out = buffer_size;
status = inflate( &cmpr_stream, Z_NO_FLUSH );
if (status == Z_OK || status == Z_STREAM_END)
{
QByteArray chunk = QByteArray::fromRawData((char *)buffer, buffer_size - cmpr_stream.avail_out);
uncompressed.append( chunk );
}
else
{
inflateEnd(&cmpr_stream);
break;
}
if (status == Z_STREAM_END)
{
inflateEnd(&cmpr_stream);
break;
}
}
while (cmpr_stream.avail_out == 0);
return uncompressed;
}
Eveything seems to work fine if the decompressed data fits into the output buffer (ie. is smaller than 16 Kb). If it doesn't, the second call to inflate returns a Z_DATA_ERROR. I know for sure the data is correct because the same chunk of data is correctly decompressed if the output buffer is made large enough.
The server doesn't return a header with the size of the uncompressed data (only the size of the compressed one) so I followed the usage instructions in zlib: http://www.zlib.net/zlib_how.html
And they do exactly what I'm doing. Any idea what I could be missing? the next_in and avail_in members in the stream seem to be updated correctly after the first iteration. Oh, and if it's any useful, the error message when the data error is issued is: "invalid distance too far back".
Any thoughts? Thanks.
The Deflate/Inflate compression/decompression algorithm uses a 32Kb circular buffer. So a 16Kb buffer can never work if the decompressed data is bigger than 16Kb. (Not strictly true, because the data is allowed to be split into blocks, but you need to assume that there may be 32Kb blocks in there.) So just set buffer_size = 32768 and you should be OK.
This is a follow up on this question: Display previously received UART values.
After implementing a circular buffer on the microcontroller, it seems that there is a problem with the pointers.
Sent on RS-232: ADE1234
Received (buffer = 8): E24AE2 / E2AE24 (Flips between the two)
Received (buffer = 16): D234E1 (A is skipped, since it is a synchro byte)
Received (RX_BufSize = 32): DE1223 / DEE123 / DE1234 / DE12E1 (flips randomly)
Expected receive: DE1234
Initialization
// Source: Thème 207 BTS électronique – Académie de Strasbourg
#define RX_BufSize 8 // Taille du Buffer_RX
char Buffer_RX[RX_BufSize]; // Buffer circulaire de réception
char *ptrRX_WRdata = Buffer_RX; // Pointeur d'écriture dans Buffer_RX
char *ptrRX_RDdata = Buffer_RX; // Pointeur de lecture dans Buffer_RX
unsigned char Buffer_Cmd[7];
Debug values displayed on LCD
//Printed debug values. Decoded output is seen via U2buf
disp_string(-62, 17, 0, "Ply2");
char U2buf[] = {slave_command, slave_pal_d, slave_bal_x,
slave_bal_y, slave_point_a, slave_point_b, '\0'};
disp_string(-37, 17, 1, U2buf);
char U3buf[] = {Buffer_RX[0], Buffer_RX[1], Buffer_RX[2],
Buffer_RX[3], Buffer_RX[4], Buffer_RX[5],
Buffer_RX[6], Buffer_RX[7], '\0'};
disp_string(-37, 27, 1, U3buf);
char U4buf[] = {Buffer_Cmd[0], Buffer_Cmd[1], Buffer_Cmd[2],
Buffer_Cmd[3], Buffer_Cmd[4], Buffer_Cmd[5],
Buffer_Cmd[6], '\0'};
disp_string(-37, 7, 1, U4buf);
Receive interrupt
void _ISR _NOPSV _U1RXInterrupt(void){
IFS0bits.U1RXIF = 0;
while(U1STAbits.URXDA){
*ptrRX_WRdata++=U1RXREG;
if (ptrRX_WRdata == Buffer_RX+RX_BufSize) ptrRX_WRdata = Buffer_RX;
}
if (U1STAbits.OERR){
U1STAbits.OERR = 0;
}
}
Functions from source
int ReadRXD(char *c){
if (ptrRX_RDdata==ptrRX_WRdata) return(0); // Pas de caractère reçu
else{
*c=*ptrRX_RDdata++;
if (ptrRX_RDdata==Buffer_RX+RX_BufSize) ptrRX_RDdata=Buffer_RX;
return(1);
}
}
void Detect_Cmd_RXD(void){
int i;
char c;
if (!ReadRXD(&c)) return;
ACL_XY_AFFICHER_CARACTERE(5, 3,256+'Z',1);
ACL_XY_AFFICHER_CARACTERE(25, 3,256+c,1);
for (i=1; i<7; i++) Buffer_Cmd[i-1]=Buffer_Cmd[i];
Buffer_Cmd[6]=c;
if (Buffer_Cmd[0]=='A'){ //&& (Buffer_Cmd[4]==0xAA)){
ACL_XY_AFFICHER_CARACTERE(15, 3,256+'Q',1);
slave_command = Buffer_Cmd[1];
slave_pal_d = Buffer_Cmd[2];
if (system_player == 2){
slave_bal_x = Buffer_Cmd[3];
slave_bal_y = Buffer_Cmd[4];
slave_point_a = Buffer_Cmd[5];
slave_point_b = Buffer_Cmd[6];
}
}
}
Detect_Cmd_RXD is called every 1/256th of a second. During that time, at least 7 values will have been sent in the UART receive buffer.
Could it be possible that the write process is so fast that it catches up on the read pointer? What can I do to solve this problem besides calling Detect_Cmd_RXD more often?
First step: Set a flag in the interrupt routine if the buffer overruns, and check for overruns in the Detect_Cmd_RXD routine. See how changing the buffer size affects the number of overruns.
Second step: If you get to a buffer size where there are no overruns, and still have corruption, take a good look at the interrupt routine. UARTs can be quite sensitive to how quickly you access their registers, or the order of operations. Check the hardware datasheet and verify that you are reading it correctly - better still, find some sample code that does similar things to what you want to do. The repeated characters when buffer size is 32 could be you reading the data register twice before the status bit has had a chance to settle down.
Shouldn't IFS0bits.U1RXIF = 0; be set at the end of the routine?
Afaik it ends the interrupt and allows a new one.