Related
Thank you so much for answering this question.
I use lame and I want to decode mp3 file to wav.
I succeeded in decoding mp3 files into wav files through several searches.
However, the size of the wav file is created too large and an error message appears.
Media player error message :
This file cannot be played. The file format may not be supported, the file extension may be incorrect, or the file may be corrupted.
If you know my problem, please give me some advice.
Thank you
HEADER FILE
#pragma once
#ifndef _LAME_HELPER_H_
#define _LAME_HELPER_H_
#include <windows.h>
#include "lame.h"
#define LH_STARTED WM_USER+1
#define LH_COMPUTED WM_USER+2
#define LH_DONE WM_USER+3
#define LH_ERROR WM_USER+4
#define MAX_THREAD_COUNT 5
enum encode_mode_e
{
EM_ABR,
EM_CBR,
EM_VBR
};
enum encode_channel_e
{
EC_MONO,
EC_STEREO
};
enum bitrate_e
{
BR_8kbps = 8,
BR_16kbps = 16,
BR_24kbps = 24,
BR_32kbps = 32,
BR_40kbps = 40,
BR_48kbps = 48,
BR_56kbps = 56,
BR_64kbps = 64,
BR_80kbps = 80,
BR_96kbps = 96,
BR_112kbps = 112,
BR_128kbps = 128,
BR_144kbps = 144,
BR_160kbps = 160,
BR_192kbps = 192,
BR_224kbps = 224,
BR_256kbps = 256,
BR_320kbps = 320
};
enum samplerate_e
{
SR_8khz = 8000,
SR_11khz = 11025,
SR_12khz = 12000,
SR_16khz = 16000,
SR_22khz = 22050,
SR_24khz = 24000,
SR_32khz = 32000,
SR_44khz = 44100,
SR_48khz = 48000
};
struct settings_t
{
char* title;
char* artist;
char* album;
char* comment;
char* year;
char* track;
char* genre;
char* albumart;
encode_channel_e channels;
bitrate_e abr_bitrate;
bitrate_e cbr_bitrate;
int quality;
encode_mode_e enc_mode;
samplerate_e resample_frequency;
samplerate_e in_samplerate;
//The constructor; used to set default values
settings_t();
};
class CLameHelper; //lameHelper prototype, needed because of struct StaticParam_t
//Use to hold parameters for the thread function
struct StaticParam_t
{
char* pcm;
char* mp3;
settings_t settings;
WNDPROC callback_proc;
CLameHelper* lhObj;
};
class CLameHelper
{
public :
static const int PCM_SIZE = 4096;
static const int MP3_SIZE = 4096;
HANDLE m_hThread[MAX_THREAD_COUNT];
StaticParam_t* m_phSParam[MAX_THREAD_COUNT];
static int Decode_s(void* pParam);
void WriteWaveHeader(FILE* const, int, int, int, int);
void Write32BitLowHigh(FILE*, int);
void Write16BitLowHigh(FILE*, int);
int SetID3AlbumArt(lame_t gfp, char const* szFileName);
void errorHandler(char*);
char errMsg[1000];
public:
CLameHelper();
~CLameHelper();
int Decode(char* szMp3_in, char* szPcm_out);
int Decode(char* szMp3_in, char* szPcm_out, WNDPROC callback_proc);
};
#endif
CPP FILE
#include "stdafx.h"
#include "LameHelper.h"
settings_t::settings_t()
{
//Setting the default values
title = "";
artist = "";
album = "";
comment = "";
year = "";
track = "";
genre = "";
albumart = NULL;
channels = EC_STEREO;
abr_bitrate = BR_128kbps;
cbr_bitrate = BR_128kbps;
quality = 5;
enc_mode = EM_CBR;
resample_frequency = SR_44khz;
in_samplerate = SR_44khz;
}
CLameHelper::CLameHelper()
{
//Initialize to NULL, aids deletion/closing later
for(int i = 0; i < MAX_THREAD_COUNT; i++)
{
m_hThread[i] = NULL;
m_phSParam[i] = NULL;
}
}
CLameHelper::~CLameHelper()
{
//Destroy all declared objects
for(int i = 0; i < MAX_THREAD_COUNT; i++)
{
if(m_hThread[i] != NULL)
CloseHandle(m_hThread[i]);
if(m_phSParam[i] != NULL)
delete m_phSParam[i];
}
}
int CLameHelper::SetID3AlbumArt(lame_t gfp, char const* szFileName)
{
int iResult = -1;
FILE *pFileName = 0;
char *szAlbumart = 0;
if(szFileName == NULL)
{
return 0;
}
pFileName = fopen(szFileName, "rb");
if(!pFileName)
{
iResult = 1;
}
else
{
size_t size;
fseek(pFileName, 0, SEEK_END);
size = ftell(pFileName);
fseek(pFileName, 0, SEEK_SET);
szAlbumart = (char*)malloc(size);
if(!szAlbumart)
{
iResult = 2;
}
else
{
if(fread(szAlbumart, 1, size, pFileName) != size)
{
iResult = 3;
}
else
{
iResult = (gfp, szAlbumart, size) ? 4 : 0;
}
free(szAlbumart);
}
fclose(pFileName);
}
switch(iResult)
{
case 1:
sprintf(errMsg, "WARNING: could not find file '%s' for szAlbumart.\n", szFileName);
errorHandler(errMsg);
break;
case 2:
errorHandler("WARNING: insufficient memory for reading the szAlbumart.\n");
break;
case 3:
sprintf(errMsg, "WARNING: read error in '%s' for szAlbumart.\n", szFileName);
errorHandler(errMsg);
break;
case 4:
sprintf(errMsg, "WARNING: unsupported image: '%s' for szAlbumart. Specify JPEG/PNG/GIF image\n", szFileName);
errorHandler(errMsg);
break;
default:
break;
}
return iResult;
}
void CLameHelper::Write16BitLowHigh(FILE * fp, int val)
{
unsigned char bytes[2];
bytes[0] = (val & 0xff);
bytes[1] = ((val >> 8) & 0xff);
fwrite(bytes, 1, 2, fp);
}
void CLameHelper::Write32BitLowHigh(FILE * fp, int val)
{
unsigned char bytes[4];
bytes[0] = (val & 0xff);
bytes[1] = ((val >> 8) & 0xff);
bytes[2] = ((val >> 16) & 0xff);
bytes[3] = ((val >> 24) & 0xff);
fwrite(bytes, 1, 4, fp);
}
void CLameHelper::WriteWaveHeader(FILE * const fp, int pcmbytes, int freq, int channels, int bits)
{
int bytes = (bits + 7) / 8;
/* quick and dirty, but documented */
fwrite("RIFF", 1, 4, fp); /* label */
Write32BitLowHigh(fp, pcmbytes + 44 - 8); /* length in bytes without header */
fwrite("WAVEfmt ", 2, 4, fp); /* 2 labels */
Write32BitLowHigh(fp, 2 + 2 + 4 + 4 + 2 + 2); /* length of PCM format declaration area */
Write16BitLowHigh(fp, 1); /* is PCM? */
Write16BitLowHigh(fp, channels); /* number of channels */
Write32BitLowHigh(fp, freq); /* sample frequency in [Hz] */
Write32BitLowHigh(fp, freq * channels * bytes); /* bytes per second */
Write16BitLowHigh(fp, channels * bytes); /* bytes per sample time */
Write16BitLowHigh(fp, bits); /* bits per sample */
fwrite("data", 1, 4, fp); /* label */
Write32BitLowHigh(fp, pcmbytes); /* length in bytes of raw PCM data */
}
int CLameHelper::Decode(char* szMp3_in, char* szPcm_out)
{
return Decode(szMp3_in, szPcm_out, NULL);
}
//the static function used for the thread
int CLameHelper::Decode_s(void* param)
{
StaticParam_t* sp = (StaticParam_t*)param;
char* szPcm_out = sp->pcm;
char* szMp3_in = sp->mp3;
WNDPROC callback_proc = sp->callback_proc;
CLameHelper* lh = (CLameHelper*)sp->lhObj;
return lh->Decode(szMp3_in, szPcm_out, callback_proc);
}
int CLameHelper::Decode(char* szMp3_in, char* szPcm_out, WNDPROC callback_proc)
{
int read, i, samples;
long wavsize = 0; // use to count the number of mp3 byte read, this is used to write the length of the wave file
long cumulative_read = 0;
short int pcm_l[PCM_SIZE], pcm_r[PCM_SIZE];
unsigned char mp3_buffer[MP3_SIZE];
FILE* mp3 = fopen(szMp3_in, "rb");
if(mp3 == NULL)
{
if(callback_proc != NULL)
{
callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -1, NULL);
}
sprintf(errMsg, "FATAL ERROR: file '%s' can't be open for read. Aborting!\n", szMp3_in);
errorHandler(errMsg);
return -1;
}
fseek(mp3, 0, SEEK_END);
long MP3_total_size = ftell(mp3);
fseek(mp3, 0, SEEK_SET);
FILE* pcm = fopen(szPcm_out, "wb");
if(pcm == NULL)
{
if(callback_proc != NULL)
{
callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -1, NULL);
}
sprintf(errMsg, "FATAL ERROR: file '%s' can't be open for write. Aborting!\n", szPcm_out);
errorHandler(errMsg);
return -1;
}
lame_t lame = lame_init();
lame_set_decode_only(lame, 1);
if(lame_init_params(lame) == -1)
{
if(callback_proc != NULL)
{
callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -2, NULL);
}
sprintf(errMsg, "FATAL ERROR: parameters failed to initialize properly in lame. Aborting!\n", szPcm_out);
errorHandler(errMsg);
return -2;
}
hip_t hip = hip_decode_init();
mp3data_struct mp3data;
memset(&mp3data, 0, sizeof(mp3data));
int nChannels = -1;
int nSampleRate = -1;
int mp3_len;
if(callback_proc != NULL)
{
callback_proc((HWND)GetModuleHandle(NULL), LH_STARTED, NULL, NULL);
}
while((read = fread(mp3_buffer, sizeof(char), MP3_SIZE, mp3)) > 0)
{
mp3_len = read;
cumulative_read += read * sizeof(char);
do
{
samples = hip_decode1_headers(hip, mp3_buffer, mp3_len, pcm_l, pcm_r, &mp3data);
wavsize += samples;
if(mp3data.header_parsed == 1)//header is gotten
{
if(nChannels < 0)//reading for the first time
{
//Write the header
WriteWaveHeader(pcm, 0x7FFFFFFF, mp3data.samplerate, mp3data.stereo, 16); //unknown size, so write maximum 32 bit signed value
}
nChannels = mp3data.stereo;
nSampleRate = mp3data.samplerate;
}
if(samples > 0 && mp3data.header_parsed != 1)
{
errorHandler("WARNING: lame decode error occured!");
break;
}
if(samples > 0)
{
for(i = 0 ; i < samples; i++)
{
fwrite((char*)&pcm_l[i], sizeof(char), sizeof(pcm_l[i]), pcm);
if(nChannels == 2)
{
fwrite((char*)&pcm_r[i], sizeof(char), sizeof(pcm_r[i]), pcm);
}
}
}
mp3_len = 0;
if(callback_proc != NULL)
{
int percentage = ((float)cumulative_read/MP3_total_size)*100;
callback_proc((HWND)GetModuleHandle(NULL), LH_COMPUTED, percentage, NULL);
}
}while(samples>0);
}
i = (16 / 8) * mp3data.stereo;
if (wavsize <= 0)
{
wavsize = 0;
}
else if (wavsize > 0xFFFFFFD0 / i)
{
wavsize = 0xFFFFFFD0;
}
else
{
wavsize *= i;
}
if(!fseek(pcm, 0l, SEEK_SET))//seek back and adjust length
WriteWaveHeader(pcm, (int) wavsize, mp3data.samplerate, mp3data.stereo, 16);
else
errorHandler("WARNING: can't seek back to adjust length in wave header!");
hip_decode_exit(hip);
lame_close(lame);
fclose(mp3);
fclose(pcm);
if(callback_proc != NULL)
{
callback_proc((HWND)GetModuleHandle(NULL), LH_DONE, NULL, NULL);
}
return 0;
}
void CLameHelper::errorHandler(char* msg)
{
printf("%s\n", msg);
}
I'm in the process of working on a kernel program to handle printing capabilities of input for a custom OS. I'm following Poncho's 2nd YouTube Video series found here, I'm currently on Video 4 in the series where he starts to add numerical types as inputs to the renderer's print function. Now, my code isn't exactly like his as I made some modifications.
-Note- This won't compile directly as there is no main function. _start is being called or invoked by a bootloader that isn't shown here, I will however, add it to the bottom of this question.
When I use the class's print function like this within my kernel:
#include "BasicRenderer.h"
extern "C" void _start(Framebuffer* framebuffer, PSF1_FONT** fonts) {
BasicRenderer = renderer(framebuffer, fonts);
renderer.Print("This is some text");
renderer.Print('\n');
renderer.Print(uint64_t(123456789));
renderer.Print('\n');
renderer.Print(int64_t(-123456789));
return;
}
And I run the kernel in emu. I'm getting the following output displayed:
This is some text
123456789
-123456789
The above is correct, however, when I try to incorporate the ability to parse a newline set of characters being either \n or \0 within of a const char* that acts as a string as seen in the following example:
#include "BasicRenderer.h"
extern "C" void _start(Framebuffer* framebuffer, PSF1_FONT** fonts) {
BasicRenderer = renderer(framebuffer, fonts);
renderer.Print("This is some text\n");
renderer.Print(uint64_t(123456789));
renderer.Print('\n');
renderer.Print(int64_t(-123456789));
return;
}
And now the displayed output is:
This is some text
123456789
-123456789
Here, the output in the second line has a space preceding the numerical value to be displayed after the call to Print() that has a \n within its string. I'm not sure what is causing this in my code. Does it have to do with the while condition or how I'm incrementing and indexing into the character string within BasicRenderer::Print(const char* str)? Or is it coming from BasicRender::PutChar(char c)? Or is it within one of the to_string() functions?
Here is the relevant implementation code...
BasicRenderer.cpp
#include "BasicRenderer.h"
void BasicRenderer::Print(const char* str) {
char* chr = (char*)str;
while(*chr != 0) {
if ( (*chr == '\\') && ((*chr+1 == 'n') || (*chr+1 == '0')) ) {
PutChar('\n');
chr++;
chr++;
} else {
PutChar(*chr);
cursor_position_.x += 8;
if (cursor_position_.x + 8 > framebuffer_->Width) {
cursor_position_.x = 0;
cursor_position_.y += 16;
}
chr++;
}
}
}
void BasicRenderer::Print(uint64_t val) {
const char* str = to_string(val);
Print(str);
}
void BasicRenderer::Print(int64_t val) {
const char* str = to_string(val);
Print(str);
}
void BasicRenderer::PutChar(char c) {
if (c == '\n' || c == '\0') {
cursor_position_.x = 0;
cursor_position_.y += 16;
} else {
unsigned int* pixPtr = (unsigned int*)framebuffer_->BaseAddress;
char* fontPtr = (char*)selected_font_->glyphBuffer + (c * selected_font_->psf1_Header->charsize);
for (unsigned long y = cursor_position_.y; y < cursor_position_.y + 16; y++) {
for (unsigned long x = cursor_position_.x; x < cursor_position_.x + 8; x++) {
if ((*fontPtr & (0b10000000 >> (x - cursor_position_.x))) > 0) {
*(unsigned int*)(pixPtr + x + (y * framebuffer_->PixelsPerScanLine)) = font_color_;
}
}
fontPtr++;
}
}
}
cstr.cpp
#include "cstr.h"
const char* to_string(uint64_t value) {
static char output_uint_buffer[128];
uint8_t size = 0;
uint64_t sizeTest = value;
while (sizeTest / 10 > 0) {
sizeTest /= 10;
size++;
}
uint8_t idx = 0;
while (value / 10 > 0) {
uint8_t remainder = value % 10;
value /= 10;
output_uint_buffer[size - idx] = remainder + '0';
idx++;
}
uint8_t remainder = value % 10;
output_uint_buffer[size-idx] = remainder + '0';
output_uint_buffer[size + 1] = 0;
return output_uint_buffer;
}
const char* to_string(int64_t value) {
static char output_int_buffer[128];
uint8_t isNegative = 0;
if (value < 0) {
isNegative = 1;
value *= -1;
output_int_buffer[0] = '-';
}
uint8_t size = 0;
uint64_t sizeTest = value;
while (sizeTest / 10 > 0) {
sizeTest /= 10;
size++;
}
uint8_t idx = 0;
while (value / 10 > 0) {
uint8_t remainder = value % 10;
value /= 10;
output_int_buffer[isNegative + size - idx] = remainder + '0';
idx++;
}
uint8_t remainder = value % 10;
output_int_buffer[isNegative + size - idx] = remainder + '0';
output_int_buffer[isNegative + size + 1] = 0;
return output_int_buffer;
}
And here is the rest of the declarations...
BasicRender.h
#pragma once
#include "cstr.h"
#include "math.h"
#include "framebuffer.h"
#include "SimpleFonts.h"
class BasicRenderer {
public:
BasicRenderer(Framebuffer* framebuffer, PSF1_FONT** fonts) :
framebuffer_{framebuffer},
fonts_{fonts},
cursor_position_({0,0}),
selected_font_{fonts_[0]},
font_color_{0xFFFFFFFF}
{}
void Print(const char* str);
void Print(char c) { PutChar(c); }
void Print(uint64_t val);
void Print(int64_t val);
private:
void PutChar(char c);
Framebuffer* framebuffer_;
Point cursor_position_;
PSF1_FONT** fonts_;
PSF1_FONT* selected_font_;
unsigned int font_color_;
};
cstr.h
#pragma once
#include <stdint.h>
const char* to_string(uint64_t value);
const char* to_string(int64_t value);
math.h
#pragma once
struct Point {
unsigned int x;
unsigned int y;
};
Framebuffer.h
#pragma once
#include <stddef.h>
struct Framebuffer {
void* BaseAddress;
size_t BufferSize;
unsigned int Width;
unsigned int Height;
unsigned int PixelsPerScanLine;
};
SimpleFonts.h
#pragma once
struct PSF1_HEADER {
unsigned char magic[2];
unsigned char mode;
unsigned char charsize;
};
struct PSF1_FONT {
PSF1_HEADER* psf1_Header;
void* glyphBuffer;
};
Here is the bootloader application that invokes the above kernel.
main.c
#include <efi.h>
#include <efilib.h>
#include <elf.h>
#define PSF1_MAGIC0 0x36
#define PSF1_MAGIC1 0x04
typedef unsigned long long size_t;
typedef struct {
unsigned char magic[2];
unsigned char mode;
unsigned char charsize;
} PSF1_HEADER;
typedef struct {
PSF1_HEADER* psf1_Header;
void* glyphBuffer;
} PSF1_FONT;
typedef struct {
void* BaseAddress;
size_t BufferSize;
unsigned int Width;
unsigned int Height;
unsigned int PixelsPerScanLine;
} Framebuffer; Framebuffer framebuffer;
Framebuffer* InitializeGOP() {
EFI_GUID gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL* gop;
EFI_STATUS status;
status = uefi_call_wrapper(BS->LocateProtocol, 3, &gopGuid, NULL, (void**)&gop);
if (EFI_ERROR(status)) {
Print(L"Unable to locate GOP\n\r");
return NULL;
} else {
Print(L"GOP located\n\r");
}
framebuffer.BaseAddress = (void*)gop->Mode->FrameBufferBase;
framebuffer.BufferSize = gop->Mode->FrameBufferSize;
framebuffer.Width = gop->Mode->Info->HorizontalResolution;
framebuffer.Height = gop->Mode->Info->VerticalResolution;
framebuffer.PixelsPerScanLine = gop->Mode->Info->PixelsPerScanLine;
return &framebuffer;
}
EFI_FILE* LoadFile(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {
EFI_FILE* LoadedFile;
EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
SystemTable->BootServices->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (void**)&LoadedImage);
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* FileSystem;
SystemTable->BootServices->HandleProtocol(LoadedImage->DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (void**)&FileSystem);
if (Directory == NULL) {
FileSystem->OpenVolume(FileSystem, &Directory);
}
EFI_STATUS s = Directory->Open(Directory, &LoadedFile, Path, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY);
if (s != EFI_SUCCESS) {
return NULL;
}
return LoadedFile;
}
PSF1_FONT* LoadPSF1Font(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {
EFI_FILE* font = LoadFile(Directory, Path, ImageHandle, SystemTable);
if (font == NULL) return NULL;
PSF1_HEADER* fontHeader;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(PSF1_HEADER), (void**)&fontHeader);
UINTN size = sizeof(PSF1_HEADER);
font->Read(font, &size, fontHeader);
if (fontHeader->magic[0] != PSF1_MAGIC0 || fontHeader->magic[1] != PSF1_MAGIC1) return NULL;
UINTN glyphBufferSize = fontHeader->charsize * 256;
if (fontHeader->mode == 1) { // 512 glyph mode
glyphBufferSize *= 2;
}
void* glyphBuffer;
font->SetPosition(font, sizeof(PSF1_HEADER));
SystemTable->BootServices->AllocatePool(EfiLoaderData, glyphBufferSize, (void**)&glyphBuffer);
font->Read(font, &glyphBufferSize, glyphBuffer);
PSF1_FONT* finishedFont;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(PSF1_FONT), (void**)&finishedFont);
finishedFont->psf1_Header = fontHeader;
finishedFont->glyphBuffer = glyphBuffer;
return finishedFont;
}
int memcmp(const void* aptr, const void* bptr, size_t n) {
const unsigned char* a = aptr, *b = bptr;
for (size_t i = 0; i < n; i++) {
if (a[i] < b[i]) return -1;
else if(a[i] > b[i]) return 1;
}
return 0;
}
EFI_STATUS efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
InitializeLib(ImageHandle, SystemTable);
Print(L"Hello World!\n\r");
EFI_FILE* Kernel = LoadFile(NULL, L"kernel.elf", ImageHandle, SystemTable);
if ( Kernel == NULL) {
Print(L"Could not load kernel \n\r");
} else {
Print(L"Kernel Loaded Successfully \n\r");
}
Elf64_Ehdr header;
{
UINTN FileInfoSize;
EFI_FILE_INFO* FileInfo;
Kernel->GetInfo(Kernel, &gEfiFileInfoGuid, &FileInfoSize, NULL);
SystemTable->BootServices->AllocatePool(EfiLoaderData, FileInfoSize, (void**)&FileInfo);
Kernel->GetInfo(Kernel, &gEfiFileInfoGuid, &FileInfoSize, (void**)&FileInfo);
UINTN size = sizeof(header);
Kernel->Read(Kernel, &size, &header);
}
if (
memcmp(&header.e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0 ||
header.e_ident[EI_CLASS] != ELFCLASS64 ||
header.e_ident[EI_DATA] != ELFDATA2LSB ||
header.e_type != ET_EXEC ||
header.e_machine != EM_X86_64 ||
header.e_version != EV_CURRENT
) {
Print(L"kernel format is bad\r\n");
} else {
Print(L"kernel header successfully verified\r\n");
}
Elf64_Phdr* phdrs;
{
Kernel->SetPosition(Kernel, header.e_phoff);
UINTN size = header.e_phnum * header.e_phentsize;
SystemTable->BootServices->AllocatePool(EfiLoaderData, size, (void**)&phdrs);
Kernel->Read(Kernel, &size, phdrs);
}
for (
Elf64_Phdr* phdr = phdrs;
(char*)phdr < (char*)phdrs + header.e_phnum * header.e_phentsize;
phdr = (Elf64_Phdr*)((char*)phdr + header.e_phentsize)
) {
switch(phdr->p_type) {
case PT_LOAD: {
int pages = (phdr->p_memsz + 0x1000 - 1) / 0x1000;
Elf64_Addr segment = phdr->p_paddr;
SystemTable->BootServices->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment);
Kernel->SetPosition(Kernel, phdr->p_offset);
UINTN size = phdr->p_filesz;
Kernel->Read(Kernel, &size, (void*)segment);
break;
}
}
}
Print(L"Kernel Loaded\n\r");
void (*KernelStart)(Framebuffer*, PSF1_FONT**) = ((__attribute__((sysv_abi)) void(*)(Framebuffer*, PSF1_FONT**) ) header.e_entry);
PSF1_FONT* newFont = LoadPSF1Font(NULL, L"zap-light16.psf", ImageHandle, SystemTable);
if (newFont == NULL) {
Print(L"Font is not valid or is not found\n\r");
} else {
Print(L"Font found, char size = %d\n\r", newFont->psf1_Header->charsize);
}
PSF1_FONT* newFontExt = LoadPSF1Font(NULL, L"zap-ext-light16.psf", ImageHandle, SystemTable);
if (newFont == NULL) {
Print(L"Font is not valid or is not found\n\r");
} else {
Print(L"Font found, char size = %d\n\r", newFont->psf1_Header->charsize);
}
PSF1_FONT* fonts[] = {newFont, newFontExt};
Framebuffer* newBuffer = InitializeGOP();
Print(L"Base: 0x%x\n\rSize: 0x%x\n\rWidth: %d\n\rHeight: %d\n\rPixelsPerScanline: %d\n\r",
newBuffer->BaseAddress,
newBuffer->BufferSize,
newBuffer->Width,
newBuffer->Height,
newBuffer->PixelsPerScanLine);
KernelStart(newBuffer, fonts);
return EFI_SUCCESS; // Exit the UEFI application
}
The problem is here:
if ( (*chr == '\\') && ((*chr+1 == 'n') || (*chr+1 == '0')) ) {
PutChar('\n');
chr++;
chr++;
}
...
You should not be parsing out \n since this will be present in the string as a linefeed character. What you want instead is:
if (*chr == '\n') {
PutChar('\n');
chr++;
}
...
I use lzmaspec.cpp from 7zip library lzma1900/cpp/7zip/Bundles/Lzmaspec to decompress lzma file.
it works fine and save file correctly.
when I take main2 function and and make header file to use it in my project,it does not save the whole file.
this is lzmaspec.h
/*
* LzmaSpec.h
*
* Created on: Oct 14, 2020
* Author: za2ponubuntu1844
*/
#ifndef LZMASPEC_H_
#define LZMASPEC_H_
int main2(const char *,const char *);
#endif /* LZMASPEC_H_ */
and this is my modified main2 function
/* LzmaSpec.cpp -- LZMA Reference Decoder
2015-06-14 : Igor Pavlov : Public domain */
// This code implements LZMA file decoding according to LZMA specification.
// This code is not optimized for speed.
#include <stdio.h>
#ifdef _MSC_VER
#pragma warning(disable : 4710) // function not inlined
#pragma warning(disable : 4996) // This function or variable may be unsafe
#endif
typedef unsigned char Byte;
typedef unsigned short UInt16;
#ifdef _LZMA_UINT32_IS_ULONG
typedef unsigned long UInt32;
#else
typedef unsigned int UInt32;
#endif
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef unsigned __int64 UInt64;
#else
typedef unsigned long long int UInt64;
#endif
struct CInputStream
{
FILE *File;
UInt64 Processed;
void Init() { Processed = 0; }
Byte ReadByte()
{
int c = getc(File);
if (c < 0)
throw "Unexpected end of file";
Processed++;
return (Byte)c;
}
};
struct COutStream
{
FILE *File;
UInt64 Processed;
void Init() { Processed = 0; }
void WriteByte(Byte b)
{
if (putc(b, File) == EOF)
throw "File writing error";
Processed++;
}
};
class COutWindow
{
Byte *Buf;
UInt32 Pos;
UInt32 Size;
bool IsFull;
public:
unsigned TotalPos;
COutStream OutStream;
COutWindow(): Buf(NULL) {}
~COutWindow() { delete []Buf; }
void Create(UInt32 dictSize)
{
Buf = new Byte[dictSize];
Pos = 0;
Size = dictSize;
IsFull = false;
TotalPos = 0;
}
void PutByte(Byte b)
{
TotalPos++;
Buf[Pos++] = b;
if (Pos == Size)
{
Pos = 0;
IsFull = true;
}
OutStream.WriteByte(b);
}
Byte GetByte(UInt32 dist) const
{
return Buf[dist <= Pos ? Pos - dist : Size - dist + Pos];
}
void CopyMatch(UInt32 dist, unsigned len)
{
for (; len > 0; len--)
PutByte(GetByte(dist));
}
bool CheckDistance(UInt32 dist) const
{
return dist <= Pos || IsFull;
}
bool IsEmpty() const
{
return Pos == 0 && !IsFull;
}
};
#define kNumBitModelTotalBits 11
#define kNumMoveBits 5
typedef UInt16 CProb;
#define PROB_INIT_VAL ((1 << kNumBitModelTotalBits) / 2)
#define INIT_PROBS(p) \
{ for (unsigned i = 0; i < sizeof(p) / sizeof(p[0]); i++) p[i] = PROB_INIT_VAL; }
class CRangeDecoder
{
UInt32 Range;
UInt32 Code;
void Normalize();
public:
CInputStream *InStream;
bool Corrupted;
bool Init();
bool IsFinishedOK() const { return Code == 0; }
UInt32 DecodeDirectBits(unsigned numBits);
unsigned DecodeBit(CProb *prob);
};
bool CRangeDecoder::Init()
{
Corrupted = false;
Range = 0xFFFFFFFF;
Code = 0;
Byte b = InStream->ReadByte();
for (int i = 0; i < 4; i++)
Code = (Code << 8) | InStream->ReadByte();
if (b != 0 || Code == Range)
Corrupted = true;
return b == 0;
}
#define kTopValue ((UInt32)1 << 24)
void CRangeDecoder::Normalize()
{
if (Range < kTopValue)
{
Range <<= 8;
Code = (Code << 8) | InStream->ReadByte();
}
}
UInt32 CRangeDecoder::DecodeDirectBits(unsigned numBits)
{
UInt32 res = 0;
do
{
Range >>= 1;
Code -= Range;
UInt32 t = 0 - ((UInt32)Code >> 31);
Code += Range & t;
if (Code == Range)
Corrupted = true;
Normalize();
res <<= 1;
res += t + 1;
}
while (--numBits);
return res;
}
unsigned CRangeDecoder::DecodeBit(CProb *prob)
{
unsigned v = *prob;
UInt32 bound = (Range >> kNumBitModelTotalBits) * v;
unsigned symbol;
if (Code < bound)
{
v += ((1 << kNumBitModelTotalBits) - v) >> kNumMoveBits;
Range = bound;
symbol = 0;
}
else
{
v -= v >> kNumMoveBits;
Code -= bound;
Range -= bound;
symbol = 1;
}
*prob = (CProb)v;
Normalize();
return symbol;
}
unsigned BitTreeReverseDecode(CProb *probs, unsigned numBits, CRangeDecoder *rc)
{
unsigned m = 1;
unsigned symbol = 0;
for (unsigned i = 0; i < numBits; i++)
{
unsigned bit = rc->DecodeBit(&probs[m]);
m <<= 1;
m += bit;
symbol |= (bit << i);
}
return symbol;
}
template <unsigned NumBits>
class CBitTreeDecoder
{
CProb Probs[(unsigned)1 << NumBits];
public:
void Init()
{
INIT_PROBS(Probs);
}
unsigned Decode(CRangeDecoder *rc)
{
unsigned m = 1;
for (unsigned i = 0; i < NumBits; i++)
m = (m << 1) + rc->DecodeBit(&Probs[m]);
return m - ((unsigned)1 << NumBits);
}
unsigned ReverseDecode(CRangeDecoder *rc)
{
return BitTreeReverseDecode(Probs, NumBits, rc);
}
};
#define kNumPosBitsMax 4
#define kNumStates 12
#define kNumLenToPosStates 4
#define kNumAlignBits 4
#define kStartPosModelIndex 4
#define kEndPosModelIndex 14
#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
#define kMatchMinLen 2
class CLenDecoder
{
CProb Choice;
CProb Choice2;
CBitTreeDecoder<3> LowCoder[1 << kNumPosBitsMax];
CBitTreeDecoder<3> MidCoder[1 << kNumPosBitsMax];
CBitTreeDecoder<8> HighCoder;
public:
void Init()
{
Choice = PROB_INIT_VAL;
Choice2 = PROB_INIT_VAL;
HighCoder.Init();
for (unsigned i = 0; i < (1 << kNumPosBitsMax); i++)
{
LowCoder[i].Init();
MidCoder[i].Init();
}
}
unsigned Decode(CRangeDecoder *rc, unsigned posState)
{
if (rc->DecodeBit(&Choice) == 0)
return LowCoder[posState].Decode(rc);
if (rc->DecodeBit(&Choice2) == 0)
return 8 + MidCoder[posState].Decode(rc);
return 16 + HighCoder.Decode(rc);
}
};
unsigned UpdateState_Literal(unsigned state)
{
if (state < 4) return 0;
else if (state < 10) return state - 3;
else return state - 6;
}
unsigned UpdateState_Match (unsigned state) { return state < 7 ? 7 : 10; }
unsigned UpdateState_Rep (unsigned state) { return state < 7 ? 8 : 11; }
unsigned UpdateState_ShortRep(unsigned state) { return state < 7 ? 9 : 11; }
#define LZMA_DIC_MIN (1 << 12)
class CLzmaDecoder
{
public:
CRangeDecoder RangeDec;
COutWindow OutWindow;
bool markerIsMandatory;
unsigned lc, pb, lp;
UInt32 dictSize;
UInt32 dictSizeInProperties;
void DecodeProperties(const Byte *properties)
{
unsigned d = properties[0];
if (d >= (9 * 5 * 5))
throw "Incorrect LZMA properties";
lc = d % 9;
d /= 9;
pb = d / 5;
lp = d % 5;
dictSizeInProperties = 0;
for (int i = 0; i < 4; i++)
dictSizeInProperties |= (UInt32)properties[i + 1] << (8 * i);
dictSize = dictSizeInProperties;
if (dictSize < LZMA_DIC_MIN)
dictSize = LZMA_DIC_MIN;
}
CLzmaDecoder(): LitProbs(NULL) {}
~CLzmaDecoder() { delete []LitProbs; }
void Create()
{
OutWindow.Create(dictSize);
CreateLiterals();
}
int Decode(bool unpackSizeDefined, UInt64 unpackSize);
private:
CProb *LitProbs;
void CreateLiterals()
{
LitProbs = new CProb[(UInt32)0x300 << (lc + lp)];
}
void InitLiterals()
{
UInt32 num = (UInt32)0x300 << (lc + lp);
for (UInt32 i = 0; i < num; i++)
LitProbs[i] = PROB_INIT_VAL;
}
void DecodeLiteral(unsigned state, UInt32 rep0)
{
unsigned prevByte = 0;
if (!OutWindow.IsEmpty())
prevByte = OutWindow.GetByte(1);
unsigned symbol = 1;
unsigned litState = ((OutWindow.TotalPos & ((1 << lp) - 1)) << lc) + (prevByte >> (8 - lc));
CProb *probs = &LitProbs[(UInt32)0x300 * litState];
if (state >= 7)
{
unsigned matchByte = OutWindow.GetByte(rep0 + 1);
do
{
unsigned matchBit = (matchByte >> 7) & 1;
matchByte <<= 1;
unsigned bit = RangeDec.DecodeBit(&probs[((1 + matchBit) << 8) + symbol]);
symbol = (symbol << 1) | bit;
if (matchBit != bit)
break;
}
while (symbol < 0x100);
}
while (symbol < 0x100)
symbol = (symbol << 1) | RangeDec.DecodeBit(&probs[symbol]);
OutWindow.PutByte((Byte)(symbol - 0x100));
}
CBitTreeDecoder<6> PosSlotDecoder[kNumLenToPosStates];
CBitTreeDecoder<kNumAlignBits> AlignDecoder;
CProb PosDecoders[1 + kNumFullDistances - kEndPosModelIndex];
void InitDist()
{
for (unsigned i = 0; i < kNumLenToPosStates; i++)
PosSlotDecoder[i].Init();
AlignDecoder.Init();
INIT_PROBS(PosDecoders);
}
unsigned DecodeDistance(unsigned len)
{
unsigned lenState = len;
if (lenState > kNumLenToPosStates - 1)
lenState = kNumLenToPosStates - 1;
unsigned posSlot = PosSlotDecoder[lenState].Decode(&RangeDec);
if (posSlot < 4)
return posSlot;
unsigned numDirectBits = (unsigned)((posSlot >> 1) - 1);
UInt32 dist = ((2 | (posSlot & 1)) << numDirectBits);
if (posSlot < kEndPosModelIndex)
dist += BitTreeReverseDecode(PosDecoders + dist - posSlot, numDirectBits, &RangeDec);
else
{
dist += RangeDec.DecodeDirectBits(numDirectBits - kNumAlignBits) << kNumAlignBits;
dist += AlignDecoder.ReverseDecode(&RangeDec);
}
return dist;
}
CProb IsMatch[kNumStates << kNumPosBitsMax];
CProb IsRep[kNumStates];
CProb IsRepG0[kNumStates];
CProb IsRepG1[kNumStates];
CProb IsRepG2[kNumStates];
CProb IsRep0Long[kNumStates << kNumPosBitsMax];
CLenDecoder LenDecoder;
CLenDecoder RepLenDecoder;
void Init()
{
InitLiterals();
InitDist();
INIT_PROBS(IsMatch);
INIT_PROBS(IsRep);
INIT_PROBS(IsRepG0);
INIT_PROBS(IsRepG1);
INIT_PROBS(IsRepG2);
INIT_PROBS(IsRep0Long);
LenDecoder.Init();
RepLenDecoder.Init();
}
};
#define LZMA_RES_ERROR 0
#define LZMA_RES_FINISHED_WITH_MARKER 1
#define LZMA_RES_FINISHED_WITHOUT_MARKER 2
int CLzmaDecoder::Decode(bool unpackSizeDefined, UInt64 unpackSize)
{
if (!RangeDec.Init())
return LZMA_RES_ERROR;
Init();
UInt32 rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
unsigned state = 0;
for (;;)
{
if (unpackSizeDefined && unpackSize == 0 && !markerIsMandatory)
if (RangeDec.IsFinishedOK())
return LZMA_RES_FINISHED_WITHOUT_MARKER;
unsigned posState = OutWindow.TotalPos & ((1 << pb) - 1);
if (RangeDec.DecodeBit(&IsMatch[(state << kNumPosBitsMax) + posState]) == 0)
{
if (unpackSizeDefined && unpackSize == 0)
return LZMA_RES_ERROR;
DecodeLiteral(state, rep0);
state = UpdateState_Literal(state);
unpackSize--;
continue;
}
unsigned len;
if (RangeDec.DecodeBit(&IsRep[state]) != 0)
{
if (unpackSizeDefined && unpackSize == 0)
return LZMA_RES_ERROR;
if (OutWindow.IsEmpty())
return LZMA_RES_ERROR;
if (RangeDec.DecodeBit(&IsRepG0[state]) == 0)
{
if (RangeDec.DecodeBit(&IsRep0Long[(state << kNumPosBitsMax) + posState]) == 0)
{
state = UpdateState_ShortRep(state);
OutWindow.PutByte(OutWindow.GetByte(rep0 + 1));
unpackSize--;
continue;
}
}
else
{
UInt32 dist;
if (RangeDec.DecodeBit(&IsRepG1[state]) == 0)
dist = rep1;
else
{
if (RangeDec.DecodeBit(&IsRepG2[state]) == 0)
dist = rep2;
else
{
dist = rep3;
rep3 = rep2;
}
rep2 = rep1;
}
rep1 = rep0;
rep0 = dist;
}
len = RepLenDecoder.Decode(&RangeDec, posState);
state = UpdateState_Rep(state);
}
else
{
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
len = LenDecoder.Decode(&RangeDec, posState);
state = UpdateState_Match(state);
rep0 = DecodeDistance(len);
if (rep0 == 0xFFFFFFFF)
return RangeDec.IsFinishedOK() ?
LZMA_RES_FINISHED_WITH_MARKER :
LZMA_RES_ERROR;
if (unpackSizeDefined && unpackSize == 0)
return LZMA_RES_ERROR;
if (rep0 >= dictSize || !OutWindow.CheckDistance(rep0))
return LZMA_RES_ERROR;
}
len += kMatchMinLen;
bool isError = false;
if (unpackSizeDefined && unpackSize < len)
{
len = (unsigned)unpackSize;
isError = true;
}
OutWindow.CopyMatch(rep0 + 1, len);
unpackSize -= len;
if (isError)
return LZMA_RES_ERROR;
}
}
static void Print(const char *s)
{
fputs(s, stdout);
}
static void PrintError(const char *s)
{
fputs(s, stderr);
}
#define CONVERT_INT_TO_STR(charType, tempSize) \
void ConvertUInt64ToString(UInt64 val, char *s)
{
char temp[32];
unsigned i = 0;
while (val >= 10)
{
temp[i++] = (char)('0' + (unsigned)(val % 10));
val /= 10;
}
*s++ = (char)('0' + (unsigned)val);
while (i != 0)
{
i--;
*s++ = temp[i];
}
*s = 0;
}
void PrintUInt64(const char *title, UInt64 v)
{
Print(title);
Print(" : ");
char s[32];
ConvertUInt64ToString(v, s);
Print(s);
Print(" bytes \n");
}
int main2(const char * infile, const char *outfile)
{
try
{
Print("\nLZMA Reference Decoder 15.00 : Igor Pavlov : Public domain : 2015-04-16\n");
//if (numArgs == 1)
// Print("\nUse: lzmaSpec a.lzma outFile");
//if (numArgs != 3)
// throw "you must specify two parameters";
CInputStream inStream;
inStream.File = fopen(infile, "rb");
inStream.Init();
if (inStream.File == 0)
throw "Can't open input file";
CLzmaDecoder lzmaDecoder;
lzmaDecoder.OutWindow.OutStream.File = fopen(outfile, "wb+");
lzmaDecoder.OutWindow.OutStream.Init();
if (inStream.File == 0)
throw "Can't open output file";
Byte header[13];
int i;
for (i = 0; i < 13; i++)
header[i] = inStream.ReadByte();
lzmaDecoder.DecodeProperties(header);
printf("\nlc=%d, lp=%d, pb=%d", lzmaDecoder.lc, lzmaDecoder.lp, lzmaDecoder.pb);
printf("\nDictionary Size in properties = %u", lzmaDecoder.dictSizeInProperties);
printf("\nDictionary Size for decoding = %u", lzmaDecoder.dictSize);
UInt64 unpackSize = 0;
bool unpackSizeDefined = false;
for (i = 0; i < 8; i++)
{
Byte b = header[5 + i];
if (b != 0xFF)
unpackSizeDefined = true;
unpackSize |= (UInt64)b << (8 * i);
}
lzmaDecoder.markerIsMandatory = !unpackSizeDefined;
Print("\n");
if (unpackSizeDefined)
PrintUInt64("Uncompressed Size", unpackSize);
else
Print("End marker is expected\n");
lzmaDecoder.RangeDec.InStream = &inStream;
Print("\n");
lzmaDecoder.Create();
int res = lzmaDecoder.Decode(unpackSizeDefined, unpackSize);
PrintUInt64("Read ", inStream.Processed);
PrintUInt64("Written ", lzmaDecoder.OutWindow.OutStream.Processed);
if (res == LZMA_RES_ERROR)
throw "LZMA decoding error";
else if (res == LZMA_RES_FINISHED_WITHOUT_MARKER)
Print("Finished without end marker");
else if (res == LZMA_RES_FINISHED_WITH_MARKER)
{
if (unpackSizeDefined)
{
if (lzmaDecoder.OutWindow.OutStream.Processed != unpackSize)
throw "Finished with end marker before than specified size";
Print("Warning: ");
}
Print("Finished with end marker");
}
else
throw "Internal Error";
Print("\n");
if (lzmaDecoder.RangeDec.Corrupted)
{
Print("\nWarning: LZMA stream is corrupted\n");
}
//15-10-2020
}
catch (const char *s)
{
PrintError("\nError:\n");
PrintError(s);
PrintError("\n");
return 1;
}
catch(...)
{
PrintError("\nError\n");
return 1;
}
return 0;
}
/*
int
#ifdef _MSC_VER
__cdecl
#endif
main(int numArgs, const char *args[])
{
try { return main2(numArgs, args); }
catch (const char *s)
{
PrintError("\nError:\n");
PrintError(s);
PrintError("\n");
return 1;
}
catch(...)
{
PrintError("\nError\n");
return 1;
}
}
*/
when i debug it i find that function
void WriteByte(Byte b)
works fine but the resulting file does not have correct size.
i used this file
13h_ticks.bi5 from dukascopy
i uploaded it here
https://github.com/ahmed-allam/starting_coding
I do not know why this happens.
when i try to decompress same file using lzmaspec.cpp outside project ,it works fine.
I need guide line where the error could be?
Environment:
Ubuntu 16.04 (x64)
C++
ffmpeg
Use-case
Multiple MPEG-TS fragments are rapidly decoded ( numerous every sec )
The format of the TS fragments is dynamic and can't be known ahead of time
The first A/V frames of each fragment are needed to be extracted
Problem statement
The code bellow successfully decodes A/V, BUT, has a huge memory leak ( MBytes/sec )
According to the docs seems all memory is freed as it should ( does it... ? )
Why do I get this huge mem leak, what am I missing in the following code snap ?
struct MEDIA_TYPE {
ffmpeg::AVMediaType eType;
union {
struct {
ffmpeg::AVPixelFormat colorspace;
int width, height;
float fFPS;
} video;
struct : WAVEFORMATEX {
short sSampleFormat;
} audio;
} format;
};
struct FRAME {
enum { MAX_PALNES = 3 + 1 };
int iStrmId;
int64_t pts; // Duration in 90Khz clock resolution
uint8_t** ppData; // Null terminated
int32_t* pStride;// Zero terminated
};
HRESULT ProcessTS(IN Operation op, IN uint8_t* pTS, IN uint32_t uiBytes, bool(*cb)(IN const MEDIA_TYPE& mt, IN FRAME& frame, IN PVOID pCtx), IN PVOID pCbCtx)
{
uiBytes -= uiBytes % 188;// align to 188 packet size
struct CONTEXT {
uint8_t* pTS;
uint32_t uiBytes;
int32_t iPos;
} ctx = { pTS, uiBytes, 0 };
LOGTRACE(TSDecoder, "ProcessTS(%d, 0x%.8x, %d, 0x%.8x, 0x%.8x), this=0x%.8x\r\n", (int)op, pTS, uiBytes, cb, pCbCtx, this);
ffmpeg::AVFormatContext* pFmtCtx = 0;
if (0 == (pFmtCtx = ffmpeg::avformat_alloc_context()))
return E_OUTOFMEMORY;
ffmpeg::AVIOContext* pIoCtx = ffmpeg::avio_alloc_context(pTS, uiBytes, 0, &ctx
, [](void *opaque, uint8_t *buf, int buf_size)->int {
auto pCtx = (CONTEXT*)opaque;
int size = pCtx->uiBytes;
if (pCtx->uiBytes - pCtx->iPos < buf_size)
size = pCtx->uiBytes - pCtx->iPos;
if (size > 0) {
memcpy(buf, pCtx->pTS + pCtx->iPos, size);
pCtx->iPos += size;
}
return size;
}
, 0
, [](void* opaque, int64_t offset, int whence)->int64_t {
auto pCtx = (CONTEXT*)opaque;
switch (whence)
{
case SEEK_SET:
pCtx->iPos = offset;
break;
case SEEK_CUR:
pCtx->iPos += offset;
break;
case SEEK_END:
pCtx->iPos = pCtx->uiBytes - offset;
break;
case AVSEEK_SIZE:
return pCtx->uiBytes;
}
return pCtx->iPos;
});
pFmtCtx->pb = pIoCtx;
int iRet = ffmpeg::avformat_open_input(&pFmtCtx, "fakevideo.ts", m_pInputFmt, 0);
if (ERROR_SUCCESS != iRet) {
assert(false);
pFmtCtx = 0;// a user-supplied AVFormatContext will be freed on failure.
return E_FAIL;
}
struct DecodeContext {
ffmpeg::AVStream* pStream;
ffmpeg::AVCodec* pDecoder;
int iFramesProcessed;
};
HRESULT hr = S_OK;
int iStreamsProcessed = 0;
bool bVideoFound = false;
int64_t ptsLast = 0;
int64_t dtsLast = 0;
auto pContext = (DecodeContext*)alloca(sizeof(DecodeContext) * pFmtCtx->nb_streams);
for (unsigned int i = 0; i < pFmtCtx->nb_streams; i++) {
assert(pFmtCtx->streams[i]->index == i);
pContext[i].pStream = pFmtCtx->streams[i];
pContext[i].pDecoder = ffmpeg::avcodec_find_decoder(pFmtCtx->streams[i]->codec->codec_id);
pContext[i].iFramesProcessed= 0;
if (0 == pContext[i].pDecoder)
continue;
if ((iRet = ffmpeg::avcodec_open2(pFmtCtx->streams[i]->codec, pContext[i].pDecoder, NULL)) < 0) {
_ASSERT(FALSE);
hr = E_FAIL;
goto ErrExit;
}
}
while (S_OK == hr) {
ffmpeg::AVFrame* pFrame = 0;
ffmpeg::AVPacket pkt;
ffmpeg::av_init_packet(&pkt);
if (ERROR_SUCCESS != (iRet = ffmpeg::av_read_frame(pFmtCtx, &pkt))) {
hr = E_FAIL;
break;
}
if ((0 == dtsLast) && (0 != pkt.dts))
dtsLast = pkt.dts;
if ((0 == ptsLast) && (0 != pkt.pts))
ptsLast = pkt.pts;
DecodeContext& ctx = pContext[pkt.stream_index];
if (Operation::DECODE_FIRST_FRAME_OF_EACH_STREAM == op) {
if (iStreamsProcessed == pFmtCtx->nb_streams) {
hr = S_FALSE;
goto Next;
}
if (ctx.iFramesProcessed > 0)
goto Next;
iStreamsProcessed++;
}
if (0 == ctx.pDecoder)
goto Next;
if (0 == (pFrame = ffmpeg::av_frame_alloc())) {
hr = E_OUTOFMEMORY;
goto Next;
}
LOGTRACE(TSDecoder, "ProcessTS(%d, 0x%.8x, %d, 0x%.8x, 0x%.8x), this=0x%.8x, decode, S:%d, T:%d\r\n", (int)op, pTS, uiBytes, cb, pCbCtx, this, pkt.stream_index, ctx.pStream->codec->codec_type);
int bGotFrame = false;
int iBytesUsed = 0;
MEDIA_TYPE mt;
memset(&mt, 0, sizeof(mt));
mt.eType = ctx.pStream->codec->codec_type;
switch (mt.eType) {
case ffmpeg::AVMediaType::AVMEDIA_TYPE_AUDIO:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if((iRet = ffmpeg::avcodec_decode_audio4(ctx.pStream->codec, pFrame, &bGotFrame, &pkt)) < 0) {
hr = E_FAIL;
goto Next;
}
_ASSERT(pkt.size == iRet);
// FFMPEG AAC decoder oddity, first call to 'avcodec_decode_audio4' results mute audio where the second result the expected audio
bGotFrame = false;
if ((iRet = ffmpeg::avcodec_decode_audio4(ctx.pStream->codec, pFrame, &bGotFrame, &pkt)) < 0) {
hr = E_FAIL;
goto Next;
}
_ASSERT(pkt.size == iRet);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (false == bGotFrame)
goto Next;
iBytesUsed = ctx.pStream->codec->frame_size;
mt.format.audio.nChannels = ctx.pStream->codec->channels;
mt.format.audio.nSamplesPerSec = ctx.pStream->codec->sample_rate;
mt.format.audio.wBitsPerSample = ffmpeg::av_get_bytes_per_sample(ctx.pStream->codec->sample_fmt) * 8;
mt.format.audio.nBlockAlign = mt.format.audio.nChannels * mt.format.audio.wBitsPerSample / 8;
mt.format.audio.sSampleFormat = (short)pFrame->format;
break;
case ffmpeg::AVMediaType::AVMEDIA_TYPE_VIDEO:
if ((iRet = ffmpeg::avcodec_decode_video2(ctx.pStream->codec, pFrame, &bGotFrame, &pkt)) < 0) {
hr = E_FAIL;
break;
}
if (false == bGotFrame)
goto Next;
assert(ffmpeg::AVPixelFormat::AV_PIX_FMT_YUV420P == ctx.pStream->codec->pix_fmt);// Thats is the only color space currently supported
iBytesUsed = (ctx.pStream->codec->width * ctx.pStream->codec->height * 3) / 2;
mt.format.video.width = ctx.pStream->codec->width;
mt.format.video.height = ctx.pStream->codec->height;
mt.format.video.colorspace = ctx.pStream->codec->pix_fmt;
mt.format.video.fFPS = (float)ctx.pStream->codec->framerate.num / ctx.pStream->codec->framerate.den;
bVideoFound = true;
break;
default:
goto Next;
}
ctx.iFramesProcessed++;
{
FRAME f = { ctx.pStream->index, ((0 == ptsLast) ? dtsLast : ptsLast), (uint8_t**)pFrame->data, (int32_t*)pFrame->linesize };
if ((iRet > 0) && (false == cb(mt, f, pCbCtx)))
hr = S_FALSE;// Breaks the loop
}
Next:
ffmpeg::av_free_packet(&pkt);
if (0 != pFrame) {
//ffmpeg::av_frame_unref(pFrame);
ffmpeg::av_frame_free(&pFrame);
pFrame = 0;
}
}
ErrExit:
for (unsigned int i = 0; i < pFmtCtx->nb_streams; i++)
ffmpeg::avcodec_close(pFmtCtx->streams[i]->codec);
pIoCtx->buffer = 0;// We have allocated the buffer, no need for ffmpeg to free it 4 us
pFmtCtx->pb = 0;
ffmpeg::av_free(pIoCtx);
ffmpeg::avformat_close_input(&pFmtCtx);
ffmpeg::avformat_free_context(pFmtCtx);
return hr;
}
You need to unref the packets before reusing them. And there's no need to allocate and deallocate them all the time.
Here's how I do it which might help you:
// Initialise a packet queue
std::list<AVPacket *> packets;
...
for (int c = 0; c < MAX_PACKETS; c++) {
ff->packets.push_back(av_packet_alloc());
}
while (!quit) {
... get packet from queue
int err = av_read_frame(ff->context, packet);
... process packet (audio, video, etc)
av_packet_unref(packet); // add back to queue for reuse
}
// Release packets
while (ff->packets.size()) { // free packets
AVPacket *packet = ff->packets.front();
av_packet_free(&packet);
ff->packets.pop_front();
}
In your code you've freed a packet which wasn't allocated in the first place.
i have difficulties in using LZMA SDK in my application.
I would like to create a kind of single file compression tool. I dont need any directory support, just need only the LZMA2 stream. But i have no idea on how LZMA SDK is to be used for this.
Please can anyone give me a little example on how the LZMA SDK can be used under C++?
I think that it's a properly little example to use LZMA SDK.
/* LzmaUtil.c -- Test application for LZMA compression
2008-08-05
Igor Pavlov
public domain */
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../LzmaDec.h"
#include "../LzmaEnc.h"
#include "../Alloc.h"
const char *kCantReadMessage = "Can not read input file";
const char *kCantWriteMessage = "Can not write output file";
const char *kCantAllocateMessage = "Can not allocate memory";
const char *kDataErrorMessage = "Data error";
static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
static void SzFree(void *p, void *address) { p = p; MyFree(address); }
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
#define kInBufferSize (1 << 15)
#define kOutBufferSize (1 << 15)
unsigned char g_InBuffer[kInBufferSize];
unsigned char g_OutBuffer[kOutBufferSize];
size_t MyReadFile(FILE *file, void *data, size_t size)
{ return fread(data, 1, size, file); }
int MyReadFileAndCheck(FILE *file, void *data, size_t size)
{ return (MyReadFile(file, data, size) == size); }
size_t MyWriteFile(FILE *file, const void *data, size_t size)
{
if (size == 0)
return 0;
return fwrite(data, 1, size, file);
}
int MyWriteFileAndCheck(FILE *file, const void *data, size_t size)
{ return (MyWriteFile(file, data, size) == size); }
long MyGetFileLength(FILE *file)
{
long length;
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
return length;
}
void PrintHelp(char *buffer)
{
strcat(buffer, "\nLZMA Utility 4.58 Copyright (c) 1999-2008 Igor Pavlov 2008-04-11\n"
"\nUsage: lzma <e|d> inputFile outputFile\n"
" e: encode file\n"
" d: decode file\n");
}
int PrintError(char *buffer, const char *message)
{
strcat(buffer, "\nError: ");
strcat(buffer, message);
strcat(buffer, "\n");
return 1;
}
int PrintErrorNumber(char *buffer, SRes val)
{
sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
return 1;
}
int PrintUserError(char *buffer)
{
return PrintError(buffer, "Incorrect command");
}
#define IN_BUF_SIZE (1 << 16)
#define OUT_BUF_SIZE (1 << 16)
static int Decode(FILE *inFile, FILE *outFile, char *rs)
{
UInt64 unpackSize;
int thereIsSize; /* = 1, if there is uncompressed size in headers */
int i;
int res = 0;
CLzmaDec state;
/* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
unsigned char header[LZMA_PROPS_SIZE + 8];
/* Read and parse header */
if (!MyReadFileAndCheck(inFile, header, sizeof(header)))
return PrintError(rs, kCantReadMessage);
unpackSize = 0;
thereIsSize = 0;
for (i = 0; i < 8; i++)
{
unsigned char b = header[LZMA_PROPS_SIZE + i];
if (b != 0xFF)
thereIsSize = 1;
unpackSize += (UInt64)b << (i * 8);
}
LzmaDec_Construct(&state);
res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
if (res != SZ_OK)
return res;
{
Byte inBuf[IN_BUF_SIZE];
Byte outBuf[OUT_BUF_SIZE];
size_t inPos = 0, inSize = 0, outPos = 0;
LzmaDec_Init(&state);
for (;;)
{
if (inPos == inSize)
{
inSize = MyReadFile(inFile, inBuf, IN_BUF_SIZE);
inPos = 0;
}
{
SizeT inProcessed = inSize - inPos;
SizeT outProcessed = OUT_BUF_SIZE - outPos;
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
ELzmaStatus status;
if (thereIsSize && outProcessed > unpackSize)
{
outProcessed = (SizeT)unpackSize;
finishMode = LZMA_FINISH_END;
}
res = LzmaDec_DecodeToBuf(&state, outBuf + outPos, &outProcessed,
inBuf + inPos, &inProcessed, finishMode, &status);
inPos += (UInt32)inProcessed;
outPos += outProcessed;
unpackSize -= outProcessed;
if (outFile != 0)
MyWriteFile(outFile, outBuf, outPos);
outPos = 0;
if (res != SZ_OK || thereIsSize && unpackSize == 0)
break;
if (inProcessed == 0 && outProcessed == 0)
{
if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
res = SZ_ERROR_DATA;
break;
}
}
}
}
LzmaDec_Free(&state, &g_Alloc);
return res;
}
typedef struct _CFileSeqInStream
{
ISeqInStream funcTable;
FILE *file;
} CFileSeqInStream;
static SRes MyRead(void *p, void *buf, size_t *size)
{
if (*size == 0)
return SZ_OK;
*size = MyReadFile(((CFileSeqInStream*)p)->file, buf, *size);
/*
if (*size == 0)
return SZE_FAIL;
*/
return SZ_OK;
}
typedef struct _CFileSeqOutStream
{
ISeqOutStream funcTable;
FILE *file;
} CFileSeqOutStream;
static size_t MyWrite(void *pp, const void *buf, size_t size)
{
return MyWriteFile(((CFileSeqOutStream *)pp)->file, buf, size);
}
static SRes Encode(FILE *inFile, FILE *outFile, char *rs)
{
CLzmaEncHandle enc;
SRes res;
CFileSeqInStream inStream;
CFileSeqOutStream outStream;
CLzmaEncProps props;
enc = LzmaEnc_Create(&g_Alloc);
if (enc == 0)
return SZ_ERROR_MEM;
inStream.funcTable.Read = MyRead;
inStream.file = inFile;
outStream.funcTable.Write = MyWrite;
outStream.file = outFile;
LzmaEncProps_Init(&props);
res = LzmaEnc_SetProps(enc, &props);
if (res == SZ_OK)
{
Byte header[LZMA_PROPS_SIZE + 8];
size_t headerSize = LZMA_PROPS_SIZE;
UInt64 fileSize;
int i;
res = LzmaEnc_WriteProperties(enc, header, &headerSize);
fileSize = MyGetFileLength(inFile);
for (i = 0; i < 8; i++)
header[headerSize++] = (Byte)(fileSize >> (8 * i));
if (!MyWriteFileAndCheck(outFile, header, headerSize))
return PrintError(rs, "writing error");
if (res == SZ_OK)
res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
NULL, &g_Alloc, &g_Alloc);
}
LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
return res;
}
int main2(int numArgs, const char *args[], char *rs)
{
FILE *inFile = 0;
FILE *outFile = 0;
char c;
int res;
int encodeMode;
if (numArgs == 1)
{
PrintHelp(rs);
return 0;
}
if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1)
return PrintUserError(rs);
c = args[1][0];
encodeMode = (c == 'e' || c == 'E');
if (!encodeMode && c != 'd' && c != 'D')
return PrintUserError(rs);
{
size_t t4 = sizeof(UInt32);
size_t t8 = sizeof(UInt64);
if (t4 != 4 || t8 != 8)
return PrintError(rs, "LZMA UTil needs correct UInt32 and UInt64");
}
inFile = fopen(args[2], "rb");
if (inFile == 0)
return PrintError(rs, "Can not open input file");
if (numArgs > 3)
{
outFile = fopen(args[3], "wb+");
if (outFile == 0)
return PrintError(rs, "Can not open output file");
}
else if (encodeMode)
PrintUserError(rs);
if (encodeMode)
{
res = Encode(inFile, outFile, rs);
}
else
{
res = Decode(inFile, outFile, rs);
}
if (outFile != 0)
fclose(outFile);
fclose(inFile);
if (res != SZ_OK)
{
if (res == SZ_ERROR_MEM)
return PrintError(rs, kCantAllocateMessage);
else if (res == SZ_ERROR_DATA)
return PrintError(rs, kDataErrorMessage);
else
return PrintErrorNumber(rs, res);
}
return 0;
}
int MY_CDECL main(int numArgs, const char *args[])
{
char rs[800] = { 0 };
int res = main2(numArgs, args, rs);
printf(rs);
return res;
}
Also you can see it at:
http://read.pudn.com/downloads151/sourcecode/zip/656407/7z460/C/LzmaUtil/LzmaUtil.c__.htm
http://read.pudn.com/downloads157/sourcecode/zip/698262/LZMA/LzmaUtil.c__.htm
I recently found a nice example, written in C++. Credit goes to GH user Treeki who published the original gist:
// note: -D_7ZIP_ST is required when compiling on non-Windows platforms
// g++ -o lzma_sample -std=c++14 -D_7ZIP_ST lzma_sample.cpp LzmaDec.c LzmaEnc.c LzFind.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <memory>
#include "LzmaEnc.h"
#include "LzmaDec.h"
static void *_lzmaAlloc(ISzAllocPtr, size_t size) {
return new uint8_t[size];
}
static void _lzmaFree(ISzAllocPtr, void *addr) {
if (!addr)
return;
delete[] reinterpret_cast<uint8_t *>(addr);
}
static ISzAlloc _allocFuncs = {
_lzmaAlloc, _lzmaFree
};
std::unique_ptr<uint8_t[]> lzmaCompress(const uint8_t *input, uint32_t inputSize, uint32_t *outputSize) {
std::unique_ptr<uint8_t[]> result;
// set up properties
CLzmaEncProps props;
LzmaEncProps_Init(&props);
if (inputSize >= (1 << 20))
props.dictSize = 1 << 20; // 1mb dictionary
else
props.dictSize = inputSize; // smaller dictionary = faster!
props.fb = 40;
// prepare space for the encoded properties
SizeT propsSize = 5;
uint8_t propsEncoded[5];
// allocate some space for the compression output
// this is way more than necessary in most cases...
// but better safe than sorry
// (a smarter implementation would use a growing buffer,
// but this requires a bunch of fuckery that is out of
/// scope for this simple example)
SizeT outputSize64 = inputSize * 1.5;
if (outputSize64 < 1024)
outputSize64 = 1024;
auto output = std::make_unique<uint8_t[]>(outputSize64);
int lzmaStatus = LzmaEncode(
output.get(), &outputSize64, input, inputSize,
&props, propsEncoded, &propsSize, 0,
NULL,
&_allocFuncs, &_allocFuncs);
*outputSize = outputSize64 + 13;
if (lzmaStatus == SZ_OK) {
// tricky: we have to generate the LZMA header
// 5 bytes properties + 8 byte uncompressed size
result = std::make_unique<uint8_t[]>(outputSize64 + 13);
uint8_t *resultData = result.get();
memcpy(resultData, propsEncoded, 5);
for (int i = 0; i < 8; i++)
resultData[5 + i] = (inputSize >> (i * 8)) & 0xFF;
memcpy(resultData + 13, output.get(), outputSize64);
}
return result;
}
std::unique_ptr<uint8_t[]> lzmaDecompress(const uint8_t *input, uint32_t inputSize, uint32_t *outputSize) {
if (inputSize < 13)
return NULL; // invalid header!
// extract the size from the header
UInt64 size = 0;
for (int i = 0; i < 8; i++)
size |= (input[5 + i] << (i * 8));
if (size <= (256 * 1024 * 1024)) {
auto blob = std::make_unique<uint8_t[]>(size);
ELzmaStatus lzmaStatus;
SizeT procOutSize = size, procInSize = inputSize - 13;
int status = LzmaDecode(blob.get(), &procOutSize, &input[13], &procInSize, input, 5, LZMA_FINISH_END, &lzmaStatus, &_allocFuncs);
if (status == SZ_OK && procOutSize == size) {
*outputSize = size;
return blob;
}
}
return NULL;
}
void hexdump(const uint8_t *buf, int size) {
int lines = (size + 15) / 16;
for (int i = 0; i < lines; i++) {
printf("%08x | ", i * 16);
int lineMin = i * 16;
int lineMax = lineMin + 16;
int lineCappedMax = (lineMax > size) ? size : lineMax;
for (int j = lineMin; j < lineCappedMax; j++)
printf("%02x ", buf[j]);
for (int j = lineCappedMax; j < lineMax; j++)
printf(" ");
printf("| ");
for (int j = lineMin; j < lineCappedMax; j++) {
if (buf[j] >= 32 && buf[j] <= 127)
printf("%c", buf[j]);
else
printf(".");
}
printf("\n");
}
}
void testIt(const uint8_t *input, int size) {
printf("Test Input:\n");
hexdump(input, size);
uint32_t compressedSize;
auto compressedBlob = lzmaCompress(input, size, &compressedSize);
if (compressedBlob) {
printf("Compressed:\n");
hexdump(compressedBlob.get(), compressedSize);
} else {
printf("Nope, we screwed it\n");
return;
}
// let's try decompressing it now
uint32_t decompressedSize;
auto decompressedBlob = lzmaDecompress(compressedBlob.get(), compressedSize, &decompressedSize);
if (decompressedBlob) {
printf("Decompressed:\n");
hexdump(decompressedBlob.get(), decompressedSize);
} else {
printf("Nope, we screwed it (part 2)\n");
return;
}
printf("----------\n");
}
void testIt(const char *string) {
testIt((const uint8_t *)string, strlen(string));
}
int main(int argc, char **argv) {
testIt("a");
testIt("here is a cool string");
testIt("here's something that should compress pretty well: abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef");
return 0;
}
You can refer to this file on how to use lzma2。
https://github.com/Tencent/libpag/blob/aab6391e455193c8ec5b8e2031b495b3fe77b034/test/framework/utils/LzmaUtil.cpp
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making libpag available.
//
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// unless required by applicable law or agreed to in writing, software distributed under the
// license is distributed on an "as is" basis, without warranties or conditions of any kind,
// either express or implied. see the license for the specific language governing permissions
// and limitations under the license.
//
/////////////////////////////////////////////////////////////////////////////////////////////////
#include "LzmaUtil.h"
#include "test/framework/lzma/Lzma2DecMt.h"
#include "test/framework/lzma/Lzma2Enc.h"
namespace pag {
static void* LzmaAlloc(ISzAllocPtr, size_t size) {
return new uint8_t[size];
}
static void LzmaFree(ISzAllocPtr, void* address) {
if (!address) {
return;
}
delete[] reinterpret_cast<uint8_t*>(address);
}
static ISzAlloc gAllocFuncs = {LzmaAlloc, LzmaFree};
class SequentialOutStream {
public:
virtual ~SequentialOutStream() = default;
virtual bool write(const void* data, size_t size) = 0;
};
class SequentialInStream {
public:
virtual ~SequentialInStream() = default;
virtual bool read(void* data, size_t size, size_t* processedSize) = 0;
};
struct CSeqInStreamWrap {
ISeqInStream vt;
std::unique_ptr<SequentialInStream> inStream;
};
struct CSeqOutStreamWrap {
ISeqOutStream vt;
std::unique_ptr<SequentialOutStream> outStream;
};
class BuffPtrInStream : public SequentialInStream {
public:
explicit BuffPtrInStream(const uint8_t* buffer, size_t bufferSize)
: buffer(buffer), bufferSize(bufferSize) {
}
bool read(void* data, size_t size, size_t* processedSize) override {
if (processedSize) {
*processedSize = 0;
}
if (size == 0 || position >= bufferSize) {
return true;
}
auto remain = bufferSize - position;
if (remain > size) {
remain = size;
}
memcpy(data, static_cast<const uint8_t*>(buffer) + position, remain);
position += remain;
if (processedSize) {
*processedSize = remain;
}
return true;
}
private:
const uint8_t* buffer = nullptr;
size_t bufferSize = 0;
size_t position = 0;
};
class VectorOutStream : public SequentialOutStream {
public:
explicit VectorOutStream(std::vector<uint8_t>* buffer) : buffer(buffer) {
}
bool write(const void* data, size_t size) override {
auto oldSize = buffer->size();
buffer->resize(oldSize + size);
memcpy(&(*buffer)[oldSize], data, size);
return true;
}
private:
std::vector<uint8_t>* buffer;
};
class BuffPtrSeqOutStream : public SequentialOutStream {
public:
BuffPtrSeqOutStream(uint8_t* buffer, size_t size) : buffer(buffer), bufferSize(size) {
}
bool write(const void* data, size_t size) override {
auto remain = bufferSize - position;
if (remain > size) {
remain = size;
}
if (remain != 0) {
memcpy(buffer + position, data, remain);
position += remain;
}
return remain != 0 || size == 0;
}
private:
uint8_t* buffer = nullptr;
size_t bufferSize = 0;
size_t position = 0;
};
static const size_t kStreamStepSize = 1 << 31;
static SRes MyRead(const ISeqInStream* p, void* data, size_t* size) {
CSeqInStreamWrap* wrap = CONTAINER_FROM_VTBL(p, CSeqInStreamWrap, vt);
auto curSize = (*size < kStreamStepSize) ? *size : kStreamStepSize;
if (!wrap->inStream->read(data, curSize, &curSize)) {
return SZ_ERROR_READ;
}
*size = curSize;
return SZ_OK;
}
static size_t MyWrite(const ISeqOutStream* p, const void* buf, size_t size) {
auto* wrap = CONTAINER_FROM_VTBL(p, CSeqOutStreamWrap, vt);
if (wrap->outStream->write(buf, size)) {
return size;
}
return 0;
}
class Lzma2Encoder {
public:
Lzma2Encoder() {
encoder = Lzma2Enc_Create(&gAllocFuncs, &gAllocFuncs);
}
~Lzma2Encoder() {
Lzma2Enc_Destroy(encoder);
}
std::shared_ptr<Data> code(const std::shared_ptr<Data>& inputData) {
if (encoder == nullptr || inputData == nullptr || inputData->size() == 0) {
return nullptr;
}
auto inputSize = inputData->size();
CLzma2EncProps lzma2Props;
Lzma2EncProps_Init(&lzma2Props);
lzma2Props.lzmaProps.dictSize = inputSize;
lzma2Props.lzmaProps.level = 9;
lzma2Props.numTotalThreads = 4;
Lzma2Enc_SetProps(encoder, &lzma2Props);
std::vector<uint8_t> outBuf;
outBuf.resize(1 + 8);
outBuf[0] = Lzma2Enc_WriteProperties(encoder);
for (int i = 0; i < 8; i++) {
outBuf[1 + i] = static_cast<uint8_t>(inputSize >> (8 * i));
}
CSeqInStreamWrap inWrap = {};
inWrap.vt.Read = MyRead;
inWrap.inStream = std::make_unique<BuffPtrInStream>(
static_cast<const uint8_t*>(inputData->data()), inputSize);
CSeqOutStreamWrap outStream = {};
outStream.vt.Write = MyWrite;
outStream.outStream = std::make_unique<VectorOutStream>(&outBuf);
auto status =
Lzma2Enc_Encode2(encoder, &outStream.vt, nullptr, nullptr, &inWrap.vt, nullptr, 0, nullptr);
if (status != SZ_OK) {
return nullptr;
}
return Data::MakeWithCopy(&outBuf[0], outBuf.size());
}
private:
CLzma2EncHandle encoder = nullptr;
};
std::shared_ptr<Data> LzmaUtil::Compress(const std::shared_ptr<Data>& pixelData) {
Lzma2Encoder encoder;
return encoder.code(pixelData);
}
class Lzma2Decoder {
public:
Lzma2Decoder() {
decoder = Lzma2DecMt_Create(&gAllocFuncs, &gAllocFuncs);
}
~Lzma2Decoder() {
if (decoder) {
Lzma2DecMt_Destroy(decoder);
}
}
std::shared_ptr<Data> code(const std::shared_ptr<Data>& inputData) {
if (decoder == nullptr || inputData == nullptr || inputData->size() == 0) {
return nullptr;
}
auto input = static_cast<const uint8_t*>(inputData->data());
auto inputSize = inputData->size() - 9;
Byte prop = static_cast<const Byte*>(input)[0];
CLzma2DecMtProps props;
Lzma2DecMtProps_Init(&props);
props.inBufSize_ST = inputSize;
props.numThreads = 1;
UInt64 outBufferSize = 0;
for (int i = 0; i < 8; i++) {
outBufferSize |= (input[1 + i] << (i * 8));
}
auto outBuffer = new uint8_t[outBufferSize];
CSeqInStreamWrap inWrap = {};
inWrap.vt.Read = MyRead;
inWrap.inStream = std::make_unique<BuffPtrInStream>(input + 9, inputSize);
CSeqOutStreamWrap outWrap = {};
outWrap.vt.Write = MyWrite;
outWrap.outStream = std::make_unique<BuffPtrSeqOutStream>(outBuffer, outBufferSize);
UInt64 inProcessed = 0;
int isMT = false;
auto res = Lzma2DecMt_Decode(decoder, prop, &props, &outWrap.vt, &outBufferSize, 1, &inWrap.vt,
&inProcessed, &isMT, nullptr);
if (res == SZ_OK && inputSize == inProcessed) {
return Data::MakeAdopted(outBuffer, outBufferSize, Data::DeleteProc);
}
delete[] outBuffer;
return nullptr;
}
private:
CLzma2DecMtHandle decoder = nullptr;
};
std::shared_ptr<Data> LzmaUtil::Decompress(const std::shared_ptr<Data>& data) {
Lzma2Decoder decoder;
return decoder.code(data);
}
} // namespace pag