Skip to content

Commit

Permalink
Merge pull request #57 from IRFM/buffer
Browse files Browse the repository at this point in the history
Read IRMovie from buffer
  • Loading branch information
dubusster authored Nov 18, 2024
2 parents 98bc50b + 36096dd commit f279420
Show file tree
Hide file tree
Showing 12 changed files with 274 additions and 73 deletions.
53 changes: 52 additions & 1 deletion src/cpp/tools/ReadFileChunk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ void *createFileReader(FileAccess access)
return reader;
}


void destroyFileReader(void *r)
{
if (!r)
Expand Down Expand Up @@ -383,4 +384,54 @@ FileAccess createFileAccess(const char *filename, int64_t chunk_size)
res.read = &readFileChunk;
res.opaque = f;
return res;
}
}


#define MEM_BLOCK_CHUNK 4096


struct MemBlock
{
void * ptr;
int64_t size;
};

void destroyOpaqueMemoryHandle(void *opaque)
{
MemBlock *f = (MemBlock *)opaque;
delete f;
}
int64_t readMemoryChunk(void *opaque, int64_t chunk, uint8_t *buf)
{
MemBlock *f = (MemBlock *)opaque;
int64_t pos = chunk * MEM_BLOCK_CHUNK;
int64_t size = MEM_BLOCK_CHUNK;
if(pos >= f->size)
size = 0;
else if(pos + size >= f->size)
size = f->size - pos;
memcpy(buf,(char*)f->ptr + pos,size);
return size;
}
void memoryInfos(void *opaque, int64_t *fileSize, int64_t *chunkCount, int64_t *chunkSize)
{
MemBlock *f = (MemBlock *)opaque;
*fileSize = f->size;
*chunkCount = f->size / MEM_BLOCK_CHUNK + (f->size % MEM_BLOCK_CHUNK ? 1 : 0);
*chunkSize = MEM_BLOCK_CHUNK;
}

FileAccess createMemoryAccess( void *data, int64_t size)
{
MemBlock *f = new MemBlock();
f->ptr = data;
f->size = size;

FileAccess res;
res.destroy = &destroyOpaqueMemoryHandle;
res.infos = &memoryInfos;
res.read = &readMemoryChunk;
res.opaque = f;
return res;
}

5 changes: 5 additions & 0 deletions src/cpp/tools/ReadFileChunk.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ Create and return a FileAccess from a local file
*/
TOOLS_EXPORT FileAccess createFileAccess(const char *filename, int64_t chunk_size = 4096);

/**
Create and return a FileAccess working on a memory chunk
*/
TOOLS_EXPORT FileAccess createMemoryAccess( void *data, int64_t size);

/**
Create a file reader object from a #FileAccess object.
This file reader can be passed to the librir function #open_camera_file_reader().
Expand Down
13 changes: 13 additions & 0 deletions src/cpp/tools/tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ extern "C"
#include "tools.h"
#include "Log.h"
#include "FileAttributes.h"
#include "ReadFileChunk.h"


using namespace rir;

Expand Down Expand Up @@ -225,6 +227,17 @@ int attrs_read_file_reader(void *file_reader)
}
return set_void_ptr(attrs);
}

int attrs_open_from_memory(void *ptr, int64_t size)
{
void *reader = createFileReader(createMemoryAccess(ptr,size));
int res = attrs_read_file_reader(reader);
destroyFileReader(reader);
return res;
}



int attrs_open_file(const char *filename)
{
FileAttributes *attrs = new FileAttributes();
Expand Down
7 changes: 7 additions & 0 deletions src/cpp/tools/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ Log levels
Returns 0 on error.
*/
TOOLS_EXPORT int attrs_read_file_reader(void *file_reader);

/**
Read file attributes from an in-memory file.
This is a read-only version.
*/
TOOLS_EXPORT int attrs_open_from_memory(void *ptr, int64_t size);

/**
Read file attributes.
Returns the file attribute object handle.
Expand Down
39 changes: 39 additions & 0 deletions src/cpp/video_io/video_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ extern "C"
#include "IRFileLoader.h"
#include "h264.h"
#include "HCCLoader.h"
#include "ReadFileChunk.h"

using namespace rir;

#include <fstream>
Expand Down Expand Up @@ -104,6 +106,43 @@ int open_camera_file_reader(void *file_reader, int *file_format)
}
}

int open_camera_from_memory(void *ptr, int64_t size, int *file_format)
{
if (file_format)
*file_format = 0;

IRFileLoader *loader = new IRFileLoader();
void *reader = createFileReader(createMemoryAccess(ptr,size));

if (loader->openFileReader(reader))
{
if (file_format)
{
if (loader->isPCR())
*file_format = FILE_FORMAT_PCR;
else if (loader->isBIN())
*file_format = FILE_FORMAT_WEST;
else if (loader->isPCREncapsulated())
*file_format = FILE_FORMAT_PCR_ENCAPSULATED;
else if (loader->isZCompressed())
*file_format = FILE_FORMAT_ZSTD_COMPRESSED;
else if (loader->isHCC())
*file_format = FILE_FORMAT_HCC;
else if (loader->isH264())
*file_format = FILE_FORMAT_H264;
else
*file_format = FILE_FORMAT_OTHER;
}
return set_void_ptr(loader);
}
else
{
delete loader;
logError(("Unable to open camera file: wrong file format"));
return 0;
}
}

int close_camera(int cam)
{
void *camera = get_void_ptr(cam);
Expand Down
12 changes: 12 additions & 0 deletions src/cpp/video_io/video_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ extern "C"
\sa createFileReader
*/
IO_EXPORT int open_camera_file_reader(void *file_reader, int *file_format);

/**
Opens a camera video file from a memory reader (created with #createMemoryReader()) object and returns
the camera descriptor on success, NULL otherwise.
If \a file_format is not NULL, it will be set to the file type: FILE_FORMAT_PCR, FILE_FORMAT_WEST,
FILE_FORMAT_PCR_ENCAPSULATED, FILE_FORMAT_ZSTD_COMPRESSED, FILE_FORMAT_H264 or 0 on error.
The created camera object will take ownership of the file reader and will destroy it with #destroyMemoryReader()
on closing.
\sa createMemoryReader
*/
IO_EXPORT int open_camera_from_memory(void *ptr, int64_t size, int *file_format);

/**
Closes a previously opened camera or video file.
*/
Expand Down
20 changes: 15 additions & 5 deletions src/python/librir/tools/FileAttributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
@author: VM213788
"""

from os import PathLike
import numpy as np
from .. import low_level
from ..low_level.misc import *
from .rir_tools import (
attrs_open_file,
attrs_open_buffer,
attrs_close,
attrs_discard,
attrs_global_attribute_count,
Expand All @@ -18,6 +18,7 @@
attrs_global_attribute_value,
attrs_frame_attribute_name,
attrs_frame_attribute_value,
attrs_open_file,
attrs_timestamps,
attrs_set_times,
attrs_set_frame_attributes,
Expand All @@ -38,13 +39,22 @@ class FileAttributes(object):
Use the discard() function to avoid writting attributes to the file.
"""

def __init__(self, filename):
@classmethod
def from_buffer(cls, buffer: bytes):
handle = attrs_open_buffer(buffer)
return cls(handle)

@classmethod
def from_filename(cls, filename: PathLike):
handle = attrs_open_file(filename)
return cls(handle)

def __init__(self, handle):
"""
Constructor.
Create a FileAttributes object from a filename.
"""
self.handle = 0
self.handle = attrs_open_file(filename)
self.handle = handle

# read timestamps and attributes
self._timestamps = attrs_timestamps(self.handle)
Expand Down
43 changes: 34 additions & 9 deletions src/python/librir/tools/rir_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,17 @@ def blosc_decompress_zstd(src):
return out[0:ret]


def attrs_read_file_reader(data: bytes):
"""
Open attribute file reader and returns a handle to it
"""
_tools.attrs_read_file_reader.argtypes = [ct.c_char_p]
tmp = _tools.attrs_read_file_reader(data)
if tmp < 0:
raise RuntimeError("An error occured while calling 'attrs_read_file_reader'")
return tmp


def attrs_open_file(filename):
"""
Open attribute file and returns a handle to it
Expand All @@ -153,6 +164,19 @@ def attrs_open_file(filename):
return tmp


def attrs_open_buffer(buf: bytes):
"""
Open attributes from an in-memory file.
Attributes are read-only.
"""
res = _tools.attrs_open_from_memory(
ct.cast(ct.c_char_p(buf), ct.c_void_p), len(buf)
)
if res == 0:
raise RuntimeError("cannot read attributes from memory")
return res


def attrs_close(handle):
"""
Close attribute file and write remaining data
Expand Down Expand Up @@ -355,7 +379,8 @@ def attrs_timestamps(handle):

def attrs_set_times(handle, times):
_tools.attrs_set_times.argtypes = [ct.c_int, ct.POINTER(ct.c_int64), ct.c_int]
if type(times) != np.ndarray or times.dtype != np.int64:

if not isinstance(times, np.ndarray) or (times.dtype != np.int64):
times = np.array(list(times), dtype=np.int64)
tmp = _tools.attrs_set_times(
handle, times.ctypes.data_as(ct.POINTER(ct.c_int64)), int(times.shape[0])
Expand Down Expand Up @@ -392,15 +417,15 @@ def attrs_set_frame_attributes(handle, frame, attributes):
klens = []
vlens = []
for k, v in attributes.items():
if type(k) == bytes:
if isinstance(k, bytes):
ks = k
elif type(k) == str:
elif isinstance(k, str):
ks = k.encode("ascii")
else:
ks = str(k).encode("ascii")
if type(v) == bytes:
if isinstance(v, bytes):
vs = v
elif type(v) == str:
elif isinstance(v, str):
vs = v.encode("ascii")
else:
vs = str(v).encode("ascii")
Expand Down Expand Up @@ -448,15 +473,15 @@ def attrs_set_global_attributes(handle, attributes):
klens = []
vlens = []
for k, v in attributes.items():
if type(k) == bytes:
if isinstance(k, bytes):
ks = k
elif type(k) == str:
elif isinstance(k, str):
ks = k.encode("utf8")
else:
ks = str(k).encode("utf8")
if type(v) == bytes:
if isinstance(v, bytes):
vs = v
elif type(v) == str:
elif isinstance(v, str):
vs = v.encode("utf8")
else:
vs = str(v).encode("utf8")
Expand Down
Loading

0 comments on commit f279420

Please sign in to comment.