Best practice reading file as InputStream - inputstream

In Dart, I want to read BMP, so could be BIG file.
I do it like this :
var inputStream = imageFile.openInputStream();
inputStream.onData = () {
print(inputStream.available());
inputStream.read(18); // Some headers
int width = _readInt(inputStream.read(4));
int height = _readInt(inputStream.read(4));
// Another stuff ...
}
It works well with little image but when I a read a 3Mo file, the onData is executed many times. Indeed, the onData is trigged by 65536 bytes packets.
What the best practice ?
Should I write a automat with state like HEADER_STATE, COLORS_STATES, ... to set what is my reading state and consider by inputStream.read is a buffer ?
Or I miss a reader class ?
I fear to miss some bytes between 2 packets.
I'm a little disappointed about this, when I do it in java, I just write :
inputStream.read(numberOfBytes);
More easy to use.

Once you have your RandomAccessFile open, you can do something like this:
RandomAccessFile raf; // Initialized elsewhere
int bufferSize = 1024*1024; // 1 MB
int offsetIntoFile = 0;
Uint8List byteBuffer = new Uint8List(bufferSize); // 1 MB
Future<int> bytesReadFuture = raf.readList(byteBuffer, offsetIntoFile, bufferSize);
bytesReadFuture.then((bytesRead) {
Do something with byteBuffer here.
});
There is also a synchronous call readListSync.
John

Related

JavaFx media bytes

I want to create a soundwave in my java programm from an mp3 file. I researched and found out, that for wav-files I need to use the AudioInputStream and calculate an byte array... From mp3-File I am using JavaFX media and media-player. Are the bytes from the Inputstream the same like from the Javafx media.getSource().getBytes(); ? An AudioInputStream cant read mp3...
Or how am I supposed to get the values for an mp3 file for soundwave?
Byte from AudioInputStream:
AudioInputStream audioInputStream;
try {
audioInputStream = AudioSystem.getAudioInputStream(next);
int frameLength = (int) audioInputStream.getFrameLength();
int frameSize = (int) audioInputStream.getFormat().getFrameSize();
byte[] bytes = new byte[frameLength * frameSize];
g2.setColor(Color.MAGENTA);
for(int p = 0; p < bytes.length; p++){
g2.fillRect(20 + (p * 3), 50, 2, bytes[p]);
}
} catch (UnsupportedAudioFileException | IOException e) {
e.printStackTrace();
}
And from JavaFX:
Media media;
MediaPlayer player;
media = new Media("blablafile");
player = new Mediaplayer(media);
byte[] bytes = media.getSource().getBytes();
The JavaFX Media API does not provide much low-level support as of Java 10. It seems to be designed with only the necessary features to play media, not manipulate it significantly.
That being said, you might want to look at AudioSpectrumListener. I can't promise it will give you what you want (I'm not familiar with computer-audio concepts) but it may allow you to create your sound-wave; at least a crude representation.
You use an AudioSpectrumListener with a MediaPlayer using the corresponding property.
If your calculations don't have to be in real time then you can do them ahead of time using:
byte[] bytes = URI.create(media.getSource()).toURL().openStream().readAllBytes();
Note that if the media is remote, however, that you will end up downloading the bytes twice; once to get the bytes for your sound-wave and again when actually playing the media with a MediaPlayer.
Also, you'll want to do the above on a background thread and not the JavaFX Application thread to avoid the possibility of freezing the UI.

How to open a file in Qt-method but read it use C-language function?

I know Qt has a lot of good methods for reading file.But in my work , I have to open a file by using Qt and get a pointer pointing to the start address of the file.So how to do that?
Here is my codes:
char *buffer;
if(file.open(QIODevice::ReadOnly))
{
QByteArray dataArray=file.readAll();
buffer=dataArray.data();
}
char test[1024];
for(int i=0;i<1024;i++)
{
test[i]=*buffer;
buffer++;
}
I use QByteArray QIODevice::​readAll()to read all available data from the device, and returns it as a byte array.
Then I use char * QByteArray::​data() to set my pointer buffer.
But when I try to read the data by a for loop,my Qt debugger throw me an error:read access violation,so how would this happen?
BTW , the file to be read is very big so I can't use a buffer to read them all once. Instead , I have to do as what I did here. When I read a 7kb-sizes-file ,my codes runs well. When I read a 700kb-sizes-file , here comes the problem.
The reason you are getting access violation is that dataArray is declared inside if code block and goes out of scope. You want to declare the dataArray outside of that block, eg:
QByteArray dataArray;
if(file.open(QIODevice::ReadOnly))
{
dataArray = file.readAll();
}
else
{
// give error
}
char *buffer = dataArray.data();
char test[1024];
for(int i = 0; i < 1024; i++)
{
test[i] = *buffer;
buffer++;
}
There are other potential problems in your code though:
First, what if the size of data read from the file is less than 1024? Then you will be reading past the end of the buffer (more access violations).
Second, what if the file is really big? Reading all that data at once may cause swapping/paging.

How to change volume of an audio AVPacket

I have a desktop Qt-based application that fetches a sound stream from the network and plays it using QAudioOutput. I want to provide a volume control to the user so that he can reduce the volume. My code looks like this:
float volume_control = get_user_pref(); // user provided volume level {0.0,1.0}
for (;;) {
AVPacket *retrieved_pkt = get_decoded_packet_stream(); // from network stream
AVPacket *work_pkt
= change_volume(retrieved_pkt, volume_control); // this is what I need
// remaining code to play the work_pkt ...
}
How do I implement change_volume() or is there any off the shelf function that I can use?
Edit: Adding codec-related info as requested in the comments
QAudioFormat format;
format.setFrequency(44100);
format.setChannels(2);
format.setSampleSize(16);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
The following code works just fine.
// audio_buffer is a byte array of size data_size
// volume_level is a float between 0 (silent) and 1 (original volume)
int16_t * pcm_data = (int16_t*)(audio_buffer);
int32_t pcmval;
for (int ii = 0; ii < (data_size / 2); ii++) { // 16 bit, hence divided by 2
pcmval = pcm_data[ii] * volume_level ;
pcm_data[ii] = pcmval;
}
Edit: I think there is a significant scope of optimization here, since my solution is compute-intensive. I guess avcodec_decode_audio() can be used to speed it up.

QNetworkAccessManager read outgoingData and keep it in QIODevice

I'm trying to save all outgoing POST data in QtWebKit.
I do it using overriding QNetworkReply *QNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice outgoingData) method and reading an outgoingData that contains outgoing POST data.
The problem is that after reading it, the data become not available in the QIODevice.
How to save an outgoing (PUT, POST) data and keep it available for the future internal Qt operations?
If I need to use another approach to save PUT/POST data - please, let me know.
Code example:
QNetworkReply *MyNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData)
{
QByteArray bArray = outgoingData->readAll();
// save bArray (that contains POST outgoing data) somewhere
// do other things, and outgoingData now has no data anymore, as it was already read to bArray
}
I have tried
QByteArray bArray = outgoingData->readAll();
outgoingData->write(bArray);
qDebug() << bArray;
But in this case I get "QIODevice::write: ReadOnly device" message.
How to save the outgoing POST/PUT data in Qt?
Thanks.
qint64 QIODevice::peek (char * data, qint64 maxSize)
Reads at most maxSize bytes from the
device into data, without side effects
(i.e., if you call read() after
peek(), you will get the same data).
Returns the number of bytes read. If
an error occurs, such as when
attempting to peek a device opened in
WriteOnly mode, this function returns
-1.
0 is returned when no more data is
available for reading.
EDIT
Forget about peak(), it's not good in this situation. You could use it but you would have to do much work to accomplish what you ask for. Instead read Tee is for Tubes, grab code from there and use it.
Link by courtesy of peppe from #qt irc channel on http://irc.freenode.net.
I'd like to thank peppe and thiago who were so kind to discuss this problem on #qt channel with me.
In case one day you want to steal incoming (as opposed to outgoing) data from QNetworkAccessManager you'll find answer and code in How to read data from QNetworkReply being used by QWebPage? question.
Using pos() and seek() does actually not work in that special case. The idea of using peek() instead seems to be much better. But an example would be helpful. So, here an example of how to get data buffer from given QIODevice's outgoing data in function createRequest() without affecting original data.
if (outgoing != NULL)
{
const qint64 delta = 100;
qint64 length = delta;
QByteArray array;
while (true)
{
char *buffer = new char[length];
qint64 count = outgoing->peek(buffer, length);
if (count < length)
{
array = QByteArray(buffer, count);
delete buffer;
break;
}
length += delta;
delete buffer;
}
}
For an optimization you may adjust the value of 'delta'.
Save the IO device marker with QIODevice::pos(). Read data from it. Then restore the marker with QIODevice::seek().
This will only work if the device is a random access one. But I think it covers most of them.

AS3 Working With Arbitrarily Large Files

I am trying to read a very large file in AS3 and am having problems with the runtime just crashing on me. I'm currently using a FileStream to open the file asynchronously. This does not work(crashes without an Exception) for files bigger than about 300MB.
_fileStream = new FileStream();
_fileStream.addEventListener(IOErrorEvent.IO_ERROR, loadError);
_fileStream.addEventListener(Event.COMPLETE, loadComplete);
_fileStream.openAsync(myFile, FileMode.READ);
In looking at the documentation, it sounds like the FileStream class still tries to read in the entire file to memory(which is bad for large files).
Is there a more suitable class to use for reading large files? I really would like something like a buffered FileStream class that only loads the bytes from the files that are going to be read next.
I'm expecting that I may need to write a class that does this for me, but then I would need to read only a piece of a file at a time. I'm assuming that I can do this by setting the position and readAhead properties of the FileStream to read a chunk out of a file at a time. I would love to save some time if there is a class like this that already exists.
Is there a good way to process large files in AS3, without loading entire contents into memory?
You can use the fileStream.readAhead and fileStream.position properties to set how much of the file data you want read, and where in the file you want it to be read from.
Lets say you only want to read megabyte 152 of a gigabyte file. Do this;
(A gigabyte file consists of 1073741824 bytes)
(Megabyte 152 starts at 158334976 bytes)
var _fileStream = new FileStream();
_fileStream.addEventListener(Event.COMPLETE, loadComplete);
_fileStream.addEventListener(ProgressEvent.PROGRESS, onBytesRead);
_fileStream.readAead = (1024 * 1024); // Read only 1 megabyte
_fileStream.openAsync(myFile, FileMode.READ);
_fileStream.position = 158334976; // Read at this position in file
var megabyte152:ByteArray = new ByteArray();
function onBytesRead(e:ProgressEvent)
{
e.currentTarget.readBytes(megabyte152);
if (megabyte152.length == (1024 * 1024))
{
chunkReady();
}
}
function chunkReady()
{
// 1 megabyte has been read successfully \\
// No more data from the hard drive file will be read unless _fileStream.position changes \\
}
Can't you create a stream, and read a chunk of bytes at a given offset, a chunk at a time... so:
function readPortionOfFile(starting:int, size:int):ByteArray
{
var bytes:ByteArray ...
var fileStream:FileStream ...
fileStream.open(myFile);
fileStream.readBytes(bytes, starting, size);
fileStream.close();
return bytes;
}
and then repeat as required. I don't know how this works, and haven't tested it, but I was under the impression that this works.

Resources