H264 to PES packetization - c++

I have Ti DaVinci h264 encoder and I want to pack its output frames to PES. The stream is in annex B format.
I took the ffmpeg's pes header writer and made something like this:
void MediaPacket::writePesHeader(std::vector< uint8_t >& buffer)
{
int header_len, flags, len, val;
uint8_t *q = buffer.data();
*q++ = 0x00;
*q++ = 0x00;
*q++ = 0x01;
*q++ = 0xe0;
header_len = 0;
flags = 0;
if (pts != UNKNOWN) {
header_len += 5;
flags |= 0x80;
}
if (dts != UNKNOWN && pts != UNKNOWN && dts != pts) {
header_len += 5;
flags |= 0x40;
}
len = 0;
*q++ = len >> 8;
*q++ = len;
val = 0x80;
*q++ = val;
*q++ = flags;
*q++ = header_len;
if (pts != UNKNOWN) {
write_pts(q, flags >> 6, pts);
q += 5;
}
if (dts != UNKNOWN && pts != UNKNOWN && dts != pts) {
write_pts(q, 1, dts);
q += 5;
}
buffer.resize(q-buffer.data());
}
static void write_pts(uint8_t *q, int fourbits, int64_t pts)
{
int val;
val = fourbits << 4 | (((pts >> 30) & 0x07) << 1) | 1;
*q++ = val;
val = (((pts >> 15) & 0x7fff) << 1) | 1;
*q++ = val >> 8;
*q++ = val;
val = (((pts) & 0x7fff) << 1) | 1;
*q++ = val >> 8;
*q++ = val;
}
Encoder's output without headers is played fine with Totem player and avplay, but there is an error "could not find codec parameters" when headers are presented.
What am I doing wrong?

Related

Reading Files/Folders from disk with FAT12 in Own OS

I am developing an OS, I am trying to Implement FAT12 Filesystem from an Other's OS Source Code, Finally, I can Mount a FAT12 Formatted disk and Get its FAT12 Information.
It can Read DriveName ( When 'Location = 0' ).
But When I am trying to List Directories from disk, It is not Working!
Here, This is My Code to Get Directories,
void FAT12_PrintDirectories(uint32_t Location, uint32_t numEntries, uint8_t DriveNum)
{
uint8_t read[((numEntries*32)/4096)+1];
AHCI::Port* port = AHCI::GlobalAHCI->ports[0];
port->Configure();
port->buffer = (uint8_t*)GlobalAllocator.RequestPage();
memset(port->buffer, 0, ((numEntries*32)/4096)+1);
port->Read(Location /* If I write here '0' Instead of Location, then Output is Image2 */, Location+((numEntries*32)/4096)+1, port->buffer);
for (int n = 0; n < sizeof(port->buffer); n++)
{
GlobalRenderer->PutChar(port->buffer[n]);
read[n] = port->buffer[n];
}
char drivename[12];
memset(&drivename, 0, 12);
memcpy(drivename, read, 8);
if(read[9] != ' ')
{
drivename[8] = '.';
memcpy(drivename + 9, read + 8, 3);
}
drivename[11] = 0;
// Print test read
GlobalRenderer->Next();
for (int n = 0; n < sizeof(read); n++)
{
GlobalRenderer->Print("=");
GlobalRenderer->Print(to_string((uint64_t)read[n]));
}
GlobalRenderer->Next();
GlobalRenderer->Print("Listing Dirs!");
GlobalRenderer->Next();
GlobalRenderer->Print("DriveName : ");
GlobalRenderer->Print(drivename);
GlobalRenderer->Next();
uint8_t *reads = read;
GlobalRenderer->Print("Dirs : ");
GlobalRenderer->Next();
for (unsigned int i = 0; i < numEntries; i++)
{
if(!reads[11] & 0x08 || reads[11] & 0x02 || reads[0] == 0 || reads[0] == 0xE5)
{
// Print FileName
for (uint8_t j = 0; j < 11; j++)
{
if(j == 8 && reads[j] != ' ')
{
GlobalRenderer->Print(".");
}
if(reads[j] != 0x20)
{
GlobalRenderer->Print(to_string((uint64_t)reads[j]));
}
if(reads[11] & 0x10 && j == 10)
{
GlobalRenderer->Print("/");
}
uint32_t nextCluster = (reads[27] << 8) | reads[26];
uint32_t size = *(uint32_t *)&reads[28];
}
reads += 32;
}
GlobalRenderer->Print("-");
}
}
Here It is my Calling Code for that function FAT12_PrintDirectories(dirOff, 32, 0);
This time dirOff = 2097153
Output :
After 'Dirs' text - Image1
Image2
Location = ((FAT12_MOUNT *)getDiskMount(numActiveMounts).mount)->RootDirectoryOffset*512+1;

C++ base64decode returns junk data if it contains '\0'

We have an certificate file (binary) having '\0' in multiple places. While trying to decode using openssl it gives junk data while size used to be perfect.
Same code works perfectly if there is no '\0' in the base64encoded data
We tried achieving it using below code but still file is not readable
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
int in_1 = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
std::ofstream outfile;
outfile.open("output_file.pfx", std::ios::binary | std::ios::out);
bool f = isalnum(encoded_string[in_]);
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4) {
for (i = 0; i < 4; i++)
{
char_array_4[i] = base64_chars.find(char_array_4[i]);
}
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
{
if (char_array_3[i] != NULL)
{
ret += char_array_3[i];
char val = char_array_3[i];
outfile.write(&val, sizeof(char));
}
else
{
/*char str3[3155];
strcpy(str3, ret.c_str());
ret = "";
ret.append(str3, sizeof(str3));*/
ret += "NUL";
char val111 = char_array_3[i];
outfile.write(&val111, sizeof(char));
}
}
i = 0;
}
}
if (i) {
for (j = 0; j < i; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
for (j = 0; (j < i - 1); j++)
{
if (char_array_3[i] != NULL)
{
ret += char_array_3[i];
char val1 = char_array_3[i];
outfile.write(&val1, sizeof(char));
}
else
{
ret += "NUL";
char val11 = char_array_3[i];
outfile.write(&val11, sizeof(char));
}
}//ret += char_array_3[j];
}
outfile.close();
return ret;
}
int main()
{
base64_decode("U4tR8mRzyrqpNhhFjkbEe4I6LTYXhL7PxkbddNTQ1yZ6ofZ4s1R/UOQsq6x+CNxB+yddPirwT0yPgtm6IC1qYF9GGQsOqXHkpTrmXf0GiXDVpm91EMnyxtMu74B3OMIYgxmjoeua7HoKQkW6/GRuCpgWIoZQq7uOaKIsc3k9HGgfAFk6vTGER1YJlG28lOhsiGccl0EqD0uhrBGNhFERfAzB2gaJjI1oRO87Q2NbevKHeZycpyXgazvtw9JigA+Hp3+Cy9LUIRvF6k5uv0DKxOs5cynqYslb1LfKqT0IvLjBl4gNHl+pG5/Ur70XzZTiO1+n5jWITPoslZ4slVkl4qiTaqNWHgLT6aSUhWwPlvK+7wlk+st5ykAuSIE2e3Lia+omBRH2LQfG1v7KaOJApF3k4D0li/4QWOJ3zLwBDHB6WCwMQfNS8vTRWM1yIO/o9417wJEpBlcr/B308vGheoTF9+qRKGDe0M5PNHeBbEHhgNkLsKvcS/31HK6Xd36cg85yvyLghQRr9Gyn7TUU5m6f6iSlx3u+yo1vT7BBV6OjbxPklwCIYCZWIIOJq10JXC+bSGPbTKZYXjQW90URKesUOMi9s+DS7BKVEr471AnEyazividrgivfHDNWQisIcOctpDFCfEBAa28PYjIj4KJo5bDkSluRVcVDJVrP2Ns=");
return 0;
}
There is a bug in the handling of the trailing bytes, you are using i as the array index instead of j. As i can be larger than the size of char_array_3 it produces undefined behaviour. The correct code is:
for (j = 0; (j < i - 1); j++)
{
if (char_array_3[j] != NULL)
{
ret += char_array_3[j];
char val1 = char_array_3[j];
outfile.write(&val1, sizeof(char));
}
else
{
ret += "NUL";
char val11 = char_array_3[j];
outfile.write(&val11, sizeof(char));
}
}

Substitute an instruction depending on a condition

I have two for loops that I want to write in a function as one. The problem is that it differ only in one instruction
for (int i = 1; i <= fin_cabecera - 1 ; i++ ){
buffer[i] &= 0xfe;
if (bitsLetraRestantes < 0) {
bitsLetraRestantes = 7;
mask = 0x80;
letra = sms[++indiceLetra]; //*differs here*
}
char c = (letra & mask) >> bitsLetraRestantes--;
mask >>= 1;
buffer[i] ^= c;
}
And the other
for (int i = datos_fichero; i <= tamanio_en_bits + datos_fichero; i++){
buffer[i] &= 0xfe;
if (bitsLetraRestantes < 0) {
bitsLetraRestantes = 7;
mask = 0x80;
f.read(&letra, 1); //*differs here*
}
char c = (letra & mask) >> bitsLetraRestantes--;
mask >>= 1;
buffer[i] ^= c;
}
I thought in something like this:
void write_bit_by_bit(unsigned char buffer[], int from, int to, bool type) {
for (int i = to; i <= from; i++) {
buffer[i] &= 0xfe;
if (bitsLetraRestantes < 0) {
bitsLetraRestantes = 7;
mask = 0x80;
type ? (letra = sms[++indiceLetra]) : f.read(&letra, 1);
}
char c = (letra & mask) >> bitsLetraRestantes--;
mask >>= 1;
buffer[i] ^= c;
}
}
But I think there has to be a better method.
Context:
I will give more context (I will try explain it as better as I can within my language limitations). I have to read one byte each time because The Buffer variable represents a image pixel. sms is a message that have to be hidden within the image, and letra is a single char of that message. In order to not modify the aspect of the image, each bit of each character have to be written in the last bit of each pixel. Let me give you and example.
letra = 'H' // 01001000 in binary
buffer[0] = 255 // white pixel 11111111
In order to hide the H char, I will need 8 pixel:
The result will be like:
buffer[0] //11111110,
buffer[1] //11111111
buffer[2] //11111110
buffer[3] //11111110
buffer[4] //11111111
buffer[5] //11111110
buffer[6]//11111110
buffer[7]//11111110
The H is hidden in the last bit of the image. I hope I explained well.
[Solution]
Thanks to #anatolyg I've rewrited the code and now works just as I wanted. Here is how it looks:
void write_bit_by_bit(unsigned char buffer[], ifstream& f,int from, int to, char sms[], bool type){
unsigned short int indiceLetra = 0;
short int bitsLetraRestantes = 7;
unsigned char mask = 0x80; //Empezamos por el bit más significativo (10000000)
char* file_buffer;
if(type){ //Write file data
int number_of_bytes_to_read = get_file_size(f);
file_buffer = new char[number_of_bytes_to_read];
f.read(file_buffer, number_of_bytes_to_read);
}
const char* place_to_get_stuff_from = type ? file_buffer : sms;
char letra = place_to_get_stuff_from[0];
for (int i = from; i <= to; i++) {
buffer[i] &= 0xfe; //hacemos 0 último bit con máscara 11111110
//TODO: Hacer con dos for
if (bitsLetraRestantes < 0) {
bitsLetraRestantes = 7;
mask = 0x80;
letra = place_to_get_stuff_from[++indiceLetra];//letra = sms[++indiceLetra];
}
char c = (letra & mask) >> bitsLetraRestantes--;
mask >>= 1;
buffer[i] ^= c; //Almacenamos en el ultimo bit del pixel el valor del caracter
}
}
int ocultar(unsigned char buffer[],int tamImage, char sms[], int tamSms){
ifstream f(sms);
if (f) {
strcpy(sms,basename(sms));
buffer[0] = 0xff;
int fin_cabecera = strlen(sms)*8 + 1;
buffer[fin_cabecera] = 0xff;
write_bit_by_bit(buffer, f, 1, fin_cabecera -1, sms, WRITE_FILE_NAME);
int tamanio_en_bits = get_file_size(f) * 8;
int datos_fichero = fin_cabecera + 1;
write_bit_by_bit(buffer, f, datos_fichero, tamanio_en_bits + datos_fichero, sms, WRITE_FILE_DATA);
unsigned char fin_contenido = 0xff;
short int bitsLetraRestantes = 7;
unsigned char mask = 0x80;
for (int i = tamanio_en_bits + datos_fichero + 1;
i < tamanio_en_bits + datos_fichero + 1 + 8; i++) {
buffer[i] &= 0xfe;
char c = (fin_contenido & mask) >> bitsLetraRestantes--;
mask >>= 1;
buffer[i] ^= c;
}
}
return 0;
}
Since you are talking about optimization here, consider performing the read outside the loop. This will be a major optimization (reading 10 bytes at once must be quicker than reading 1 byte 10 times). This will require an additional buffer for (the file?) f.
if (!type)
{
char f_buffer[ENOUGH_SPACE];
number = calc_number_of_bytes_to_read();
f.read(f_buffer, number);
}
for (...) {
// your code
}
After you have done this, your original question is easy to answer:
const char* place_to_get_stuff_from = type ? sms : f_buffer;
for (...) {
...
letra = place_to_get_stuff_from[++indiceLetra];
...
}

Why this base64 function stop working when increasing max length?

I am using this class to encode/decode text to base64.
It works fine with MAX_LEN up to 512 but if I increase it to 1024 the decode function returns and empty var.
This is the function:
char* Base64::decode(char *src)
{
unsigned six, dix;
unsigned int d_len = MAX_LEN;
memset(dst,'\0', MAX_LEN);
unsigned s_len = strlen(src);
dix = 0;
for (six = 0; six < s_len; six += 4)
{
unsigned long sr;
unsigned ix;
sr = 0;
for (ix = 0; ix < 4; ++ix)
{
int sextet;
if (six+ix >= s_len)
return NULL;
if ((sextet = tlu(*(src+six+ix))) < 0)
break;
sr <<= 6;
sr |= (sextet & 0x3f);
}
switch (ix)
{
case 0: // end of data, no padding
return 0;
case 1: // can't happen
return NULL;
case 2: // 1 result byte
sr >>= 4;
if (dix > d_len) return NULL;
*(dst+dix) = (sr & 0xff);
++dix;
break;
case 3: // 2 result bytes
sr >>= 2;
if (dix+1 > d_len) return NULL;
*(dst+dix+1) = (sr & 0xff);
sr >>= 8;
*(dst+dix) = (sr & 0xff);
dix += 2;
break;
case 4: // 3 result bytes
if (dix+2 > d_len) return NULL;
*(dst+dix+2) = (sr & 0xff);
sr >>= 8;
*(dst+dix+1) = (sr & 0xff);
sr >>= 8;
*(dst+dix) = (sr & 0xff);
dix += 3;
break;
}
}
return dst;
}
Why could be causing this?
Odds are dst is not sized correctly to hold all 1024 bytes. Without seeing dst's declaration there is no way to be sure.

python struct.pack equivalent in c++

I want a fixed length string from a number just like struct.pack present in python but in c++. I thought of itoa (i,buffer,2) but problem can be that its length will depend on platform. Is there any way to make it independent of platform ?
If you're looking for a complete solution similar to Python's struct package, you might check out Google's Protocol Buffers Library. Using that will take care of a lot of issues (e.g. endian-ness, language-portability, cross-version compatibility) for you.
Here's a start:
typedef std::vector<uint8_t> byte_buffer;
template <std::size_t N>
void append_fixed_width(byte_buffer& buf, uintmax_t val) {
int shift = ((N - 1) * 8);
while (shift >= 0) {
uintmax_t mask = (0xff << shift);
buf.push_back(uint8_t((val & mask) >> shift));
shift -= 8;
}
}
template <typename IntType>
void append_bytes(byte_buffer& buf, IntType val) {
append_fixed_width<sizeof(IntType)>(buf, uintmax_t(val));
}
int main() { // usage example
byte_buffer bytes;
append_bytes(bytes, 1); // appends sizeof(int) bytes
append_bytes(bytes, 1ul); // appends sizeof(unsigned long) bytes
append_bytes(bytes, 'a'); // appends sizeof(int) bytes :p
append_bytes(bytes, char('a')); // appends 1 byte
return 0;
}
Append_bytes will append any integer type into a byte buffer represented using a std::vector<uint8_t>. Values are packed in big endian byte order. If you need to change this, then tweak append_fixed_width to traverse the value in a different order.
These functions build a raw byte buffer so whomever is decoding it is responsible for knowing what is in there. IIRC, this is what struct.pack does as well; in other words, the caller of struct.unpack needs to provide the same format string. You can write a variant of append_fixed_width to pack a TLV instead:
template <typename TagType, typename ValueType>
void append_tlv(byte_buffer& buf, TagType t, ValueType val) {
append_fixed_width<sizeof(TagType)>(buf, uintmax_t(t));
append_fixed_width<sizeof(std::size_t)>(buf, uintmax_t(sizeof(ValueType)));
append_fixed_width<sizeof(ValueType)>(buf, uintmax_t(val));
}
I would take a serious look at Jeremy's suggestion though. I wish that it had existed when I wrote all of the binary packing code that I have now.
You need to define an exact-width integer type through a typedef; you do that in a platform-specific manner. If you use C99, int16_t is predefined in <stdint.h>. You can then cast to that type, and type the memory representation of a variable:
int16_t val = (int16_t) orig_val;
void *buf = &val;
Notice that you still need to deal with endianness.
If you don't have C99, you can either use compile-time or run-time size tests. For compile-time tests, consider using autoconf, which already computes the sizes of the various primitive types, so that you can select a good type at compile time. At run-time, just have a series of sizeof tests. Notice that this is somewhat inappropriate for run-time, as the test will always come out with the same result. As an alternative to autoconf, you can also use compiler/system identification macros for a compile-time test.
The C++ way would be to use stringstream:
stringstream ss;
int number=/*your number here*/;
ss<<number;
and to get the buffer you'd use ss.str().c_str().
I made this implementation in c/c++ to compare the execution time of the pack function between python/php/dart/c++
https://github.com/dart-lang/sdk/issues/50708
#include <span>
#include <vector>
#include <cstdio>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include "time.h"
#include <map>
#define STRUCT_ENDIAN_NOT_SET 0
#define STRUCT_ENDIAN_BIG 1
#define STRUCT_ENDIAN_LITTLE 2
static int myendian = STRUCT_ENDIAN_NOT_SET;
void debug_print2(const char *str, std::vector<unsigned char> vec)
{
std::cout << str;
for (auto i : vec)
std::cout << i;
std::cout << "\r\n";
}
int struct_get_endian(void)
{
int i = 0x00000001;
if (((char *)&i)[0])
{
return STRUCT_ENDIAN_LITTLE;
}
else
{
return STRUCT_ENDIAN_BIG;
}
}
static void struct_init(void)
{
myendian = struct_get_endian();
}
static void pack_int16_t(unsigned char **bp, uint16_t val, int endian)
{
if (endian == myendian)
{
*((*bp)++) = val;
*((*bp)++) = val >> 8;
}
else
{
*((*bp)++) = val >> 8;
*((*bp)++) = val;
}
}
static void pack_int32_t(unsigned char **bp, uint32_t val, int endian)
{
if (endian == myendian)
{
*((*bp)++) = val;
*((*bp)++) = val >> 8;
*((*bp)++) = val >> 16;
*((*bp)++) = val >> 24;
}
else
{
*((*bp)++) = val >> 24;
*((*bp)++) = val >> 16;
*((*bp)++) = val >> 8;
*((*bp)++) = val;
}
}
static void pack_int64_t(unsigned char **bp, uint64_t val, int endian)
{
if (endian == myendian)
{
*((*bp)++) = val;
*((*bp)++) = val >> 8;
*((*bp)++) = val >> 16;
*((*bp)++) = val >> 24;
*((*bp)++) = val >> 32;
*((*bp)++) = val >> 40;
*((*bp)++) = val >> 48;
*((*bp)++) = val >> 56;
}
else
{
*((*bp)++) = val >> 56;
*((*bp)++) = val >> 48;
*((*bp)++) = val >> 40;
*((*bp)++) = val >> 32;
*((*bp)++) = val >> 24;
*((*bp)++) = val >> 16;
*((*bp)++) = val >> 8;
*((*bp)++) = val;
}
}
static int pack(void *b, const char *fmt, long long *values, int offset = 0)
{
unsigned char *buf = (unsigned char *)b;
int idx = 0;
const char *p;
unsigned char *bp;
int ep = myendian;
int endian;
bp = buf + offset;
auto bpp = &bp;
if (STRUCT_ENDIAN_NOT_SET == myendian)
{
struct_init();
}
for (p = fmt; *p != '\0'; p++)
{
auto value = values[idx];
switch (*p)
{
case '=': // native
ep = myendian;
break;
case '<': // little-endian
endian = STRUCT_ENDIAN_LITTLE;
ep = endian;
break;
case '>': // big-endian
endian = STRUCT_ENDIAN_BIG;
ep = endian;
break;
case '!': // network (= big-endian)
endian = STRUCT_ENDIAN_BIG;
ep = endian;
break;
case 'b':
*bp++ = value;
break;
case 'c':
*bp++ = value;
break;
case 'i':
if (ep == STRUCT_ENDIAN_LITTLE)
{
*bp++ = value;
*bp++ = value >> 8;
*bp++ = value >> 16;
*bp++ = value >> 24;
}
else
{
*bp++ = value >> 24;
*bp++ = value >> 16;
*bp++ = value >> 8;
*bp++ = value;
}
break;
case 'h':
if (ep == STRUCT_ENDIAN_LITTLE)
{
*bp++ = value;
*bp++ = value >> 8;
}
else
{
*bp++ = value >> 8;
*bp++ = value;
}
break;
case 'q':
if (ep == STRUCT_ENDIAN_LITTLE)
{
*bp++ = value;
*bp++ = value >> 8;
*bp++ = value >> 16;
*bp++ = value >> 24;
*bp++ = value >> 32;
*bp++ = value >> 40;
*bp++ = value >> 48;
*bp++ = value >> 56;
}
else
{
*bp++ = value >> 56;
*bp++ = value >> 48;
*bp++ = value >> 40;
*bp++ = value >> 32;
*bp++ = value >> 24;
*bp++ = value >> 16;
*bp++ = value >> 8;
*bp++ = value;
}
break;
}
idx++;
}
return (bp - buf);
}
int main()
{
time_t start, end;
time(&start);
// std::ios_base::sync_with_stdio(false);
std::vector<unsigned char> myVector{};
myVector.reserve(100000000 * 16);
for (int i = 0; i < 100000000; i++) // 100000000
{
char bytes[BUFSIZ] = {'\0'};
long long values[4] = {64, 65, 66, 67};
pack(bytes, "iiii", values);
for (int j = 0; j < 16; j++)
{
myVector.push_back(bytes[j]);
}
}
time(&end);
auto v2 = std::vector<unsigned char>(myVector.begin(), myVector.begin() + 16);
debug_print2("result: ", v2);
double time_taken = double(end - start);
std::cout << "pack time: " << std::fixed
<< time_taken << std::setprecision(5);
std::cout << " sec " << std::endl;
return 0;
}