PDA

Visualizza la versione completa : [C++] Spezzare una sequenza di byte a piacimento


gianvituzzi
05-01-2010, 01:11
Salve,

volevo sapere se in C++ esistesse una specie di funzione per spezzettare una sequenza di bytes, mi spiego meglio. Sto studiando l'encoder LAME ed ho scoperto che per ragioni intenre accetta solo 2304 Samples (Stereo: 2x1152).

Infatti la funzione:



beInitStream(&beConfig, &dwSamples, &dwMP3Buffer, &hbeStream);


mi ritorna sempre:

dwSamples = 2304;

Ora, ho settato la waveform API per accturare 5880 Bytes in 30 buffers (176400 bytes, ovvero 1 secondo di audio PCM, 441Khz, 16bit, stereo) ... (44100 *2 *2)

Per motivi che non vi sto ora a spiegare non posso settare il buffer per catturare 2304 Bytes o multipli...mi verrebbe un'audio pieno di schioppi e rumore.

Arriviamo alla CALLBACK_EVENT dove il sistema mi notifica che il buffer di 5880 bytes è "filled" quindi posso usarlo per convertirlo in MP3 tramite la beEncodeChuck() della DLL di Lame-enc.



while(1)
{
// CALLBACK EVENT
WaitForSingleObject(hevent, INFINITE);

if(buff[k].dwFlags & WHDR_DONE)
{
//buff[k].lpData is 5880 Bytes long...

while(...)
{
//encode();
}
waveInAddBuffer(hwi, &buff[k], sizeof(WAVEHDR));
}

if(k == num_buffers -1)
k=0;
else
k++;
}


Tuttavia la beEncodeChuck() si aspetta che le passi 2304 Samples al massimo...ne consegue che la potrò chiamare 3 volte con questi valori:



2304 bytes, 2304 bytes e 1272 bytes = 5880 bytes!


La mia domanda è: se ho un buffer con size 5880 bytes, come faccio a leggerlo a pezzi?

grazie

gianvituzzi
05-01-2010, 02:10
in poche parole mi piacerebbe trasformare questo blocco che legge da file. (io invece dovrei leggere da buffer LPSTR:



// Init the MP3 Stream
beInitStream(&bec, &dwSamples, &dwMP3Buffer, &hbeStream);

// Allocate MP3 buffer
PBYTE pMP3Buffer = new BYTE[dwMP3Buffer];

// Allocate WAV buffer
PSHORT pWAVBuffer = new SHORT[dwSamples];

// Convert All PCM samples
while ( ( dwRead = fread(pWAVBuffer, sizeof(SHORT), dwSamples, pFileIn)) > 0 )
{
// Encode samples
beEncodeChunk(hbeStream, dwRead, pWAVBuffer, pMP3Buffer, &dwWrite);

// write dwWrite bytes that are returned in tehe pMP3Buffer to disk
fwrite(pMP3Buffer,1,dwWrite,pFileOut) != dwWrite)
}

oregon
05-01-2010, 10:34
Per questo lavoro il C/C++ mette a disposizione i

puntatori

Utilizzane uno spostandolo dove ti serve prima di passare alla funzione di encoding.

gianvituzzi
05-01-2010, 13:54
per adesso ho provato una cosa del genere, pensi sia l'approccio giusto?



int main()
{
const char* buffer = "01234567890HELLOWORLDHOWAREYOU??";
char* chunk = new char[10];

int dwChunkLen = 10;
int dwChunkSeek = 0;
int dwLoop = 0;

while(dwLoop < 4)
{
memcpy(chunk, buffer+dwChunkSeek, dwChunkLen);
printf("%s\n", chunk);
++dwLoop;
dwChunkSeek += dwChunkLen;
}

delete[] chunk;

system("pause");
return 0;
}

gianvituzzi
05-01-2010, 14:14
diciamo così:



int main()
{
DWORD dwBuffer = 32;
DWORD dwChunk = 10;
LPSTR sBuffer = new char[dwBuffer];
LPSTR sChunk = new char[dwChunk];

sBuffer = "01234567890HELLOWORLDHOWAREYOU??";

DWORD dwChunkLen = dwChunk;
DWORD dwChunkSeek = 0;
DWORD dwLoop = 0;

while(dwLoop < 4)
{
memcpy(sChunk, sBuffer+dwChunkSeek, dwChunkLen);
printf("%s\n", sChunk);
++dwLoop;
dwChunkSeek += dwChunkLen;
}

system("pause");
return 0;
}


ora però il valore della condizione d'uscita dalla while lo scritta io, si può fare in automatico, ad esempio: DWORD dwExit = ceil(32/10) ?? e devo fare il cast di ceil?

Inoltre se volessi leggere il contenuto di un LPSTR in un SHORT dovrei fare cosi?



memcpy(pWAVChunk, sBuffer+dwChunkSeek*sizeof(SHORT), dwChunkLen);
// dove: PSHORT pWAVBuffer = new SHORT[n]


grazie

oregon
05-01-2010, 14:46
Non ho letto tutto (anche perchè tu proponi sempre n risposte ed m domande ...) ma penso possa essere l'approccio giusto, a meno di errori "tecnici" ...

gianvituzzi
06-01-2010, 02:00
allora con questo codice credo di rendere bene l'idea su quello che voglio fare.



#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

const LPSTR strFileIn = TEXT("C:\\Users\\giangaetano\\Desktop\\testcase.wav");
const LPSTR strFileOut = TEXT("C:\\Users\\giangaetano\\Desktop\\marameo.wav");

int main()
{
DWORD dwBuffer = 100000;
DWORD dwChunk = 2304;
LPSTR header = new char[44];
PBYTE pWAVBuffer = new BYTE[dwBuffer];
PBYTE pWAVChunk = new BYTE[dwChunk];
FILE* pFileIn = NULL;
DWORD dwRead = 0;

// Slurp file: pWAVBuffer contains all the data
pFileIn = fopen( strFileIn, "rb" );
if (pFileIn == NULL)
{
printf("cannot open file!\n");
return -1;
}
dwRead = fread(header, 1, 44, pFileIn);
dwRead = fread(pWAVBuffer, sizeof(BYTE), dwBuffer, pFileIn);
fclose(pFileIn);
printf("%d\n", dwRead);

// Loop thru data:
DWORD dwLoopExit = (DWORD)ceil((double)dwBuffer/dwChunk);
DWORD dwChunkSeek = 0;
DWORD dwLoop = 0;

FILE* pFileOut;
pFileOut = fopen( strFileOut, "wb" );
fwrite(header, 1, 44, pFileOut);

while (dwLoop < dwLoopExit)
{
memcpy(pWAVChunk, pWAVBuffer + dwChunkSeek, dwChunk);
dwChunkSeek += dwChunk;
++dwLoop;
fwrite(pWAVChunk, sizeof(BYTE), dwChunk, pFileOut);
printf("%d\n", dwChunkSeek);
}
fclose(pFileOut);

delete[] header;
delete[] pWAVBuffer;
delete[] pWAVChunk;

system("pause");
return 0;
}


Il codice serve solo a scopo didattico. Leggo in memoria l'intero contenuto di un file e lo riscrivo a chunks di 2304 bytes in un'altro file...il File di origine pesa 100040 Bytes (ma i primi 44 bytes sono di header, non mi servono)

Calcolando che lo voglio salvare in un unico file man mano a pezzetti di 2304 bytes l'uno, dovrò fare ceil((double)100000/2304) = 44 cicli while, di qui 43 sono chunks pieni mentre l'ultimo e nullpadded in parte...come posso evitare il nulpadded e salvare solo i testanti 928 bytes??

oregon
06-01-2010, 02:27
Calcola la parte intera della divisione

100000/2304

ovvero

43

e poi il resto

100000-(43*2304)

ovvero

928

A questo punto fai il ciclo con la scrittura "piena" per 43 volte e dopo il ciclo fai una sola scrittura della parte restante, ovvero dei 928 byte

gianvituzzi
06-01-2010, 03:11
grazie, a questo punto mi conviene fare una cosa che può sembrare andare per le lunghe ma credo funzionerà:



#include <stdlib.h>
#include <map>
#include <math.h>

int main()
{
std::map<int, int> hashChunk;

int dwBuffer = 100000;
int dwChunk = 2304;
int dwNumChunks = (int)ceil((double)dwBuffer/dwChunk);
int dwLastChunk = dwChunk-((dwChunk*dwNumChunks)-dwBuffer);

int k = 0;
while (k < dwNumChunks - 1)
{
hashChunk.insert(std::make_pair(k, dwChunk));
++k;
}
hashChunk.insert(std::make_pair(k, dwLastChunk));

int g = 0;
while (g < dwNumChunks)
{
printf("%d -> %d\n", g, hashChunk[g]);
++g;
}

system("pause");
return 0;
}


obbero un hash che contiene in key il numero del "ciclo" ed in value il relativo "buffer len" da usare...modificando ad esempio il codice precedente così:



while(dwLoop < 4)
{
memcpy(sChunk, sBuffer+dwChunkSeek, hashChunk[dwLoop]);
printf("%s\n", sChunk);
++dwLoop;
dwChunkSeek += dwChunkLen;
}


di più non so che fare...(se non dormire)

gianvituzzi
06-01-2010, 14:19
anche se hora però sono bloccato quì:



while(1)
{
if(stop_thread_flag)
break;
// CALLBACK EVENT
WaitForSingleObject(hevent, INFINITE);

if(buff[k].dwFlags & WHDR_DONE)
{
// Encode chunk by chunk
while(dwLoop < dwNumChunks)
{
// copy part of the buffer
memcpy(
pWAVChunk, buff[k].lpData + dwChunkSeek, hashChunk[dwLoop]);
// Encode samples
printf("encode\n");
result = beEncodeChunk(hbeStream,
hashChunk[dwLoop], pWAVChunk, pMP3Buffer, &dwWrite);
// Save
hFile.write((LPSTR)pMP3Buffer, dwWrite);
dwChunkSeek += hashChunk[dwLoop];
++dwLoop;
}
dwLoop = 0;
dwChunkSeek = 0;
waveInAddBuffer(hwi, &buff[k], sizeof(WAVEHDR));
}



mi va in errore: beEncodeChunk() ma sembra tutto giusto :-(

Loading