summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gnuradio-core/src/lib/io/gr_file_meta_sink.cc119
-rw-r--r--gnuradio-core/src/lib/io/gr_file_meta_sink.h15
-rw-r--r--gnuradio-core/src/lib/io/gr_file_meta_sink.i5
-rw-r--r--gnuradio-core/src/python/gnuradio/parse_file_metadata.py13
4 files changed, 96 insertions, 56 deletions
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_sink.cc b/gnuradio-core/src/lib/io/gr_file_meta_sink.cc
index 401d8299d..ebfeb4e4a 100644
--- a/gnuradio-core/src/lib/io/gr_file_meta_sink.cc
+++ b/gnuradio-core/src/lib/io/gr_file_meta_sink.cc
@@ -28,31 +28,32 @@
#include <gr_io_signature.h>
#include <stdexcept>
-#define HEADER_SIZE 117
-
gr_file_meta_sink_sptr
gr_make_file_meta_sink(size_t itemsize, const char *filename,
double samp_rate, double relative_rate,
gr_file_types type, bool complex,
+ size_t max_segment_size,
const std::string &extra_dict)
{
return gnuradio::get_initial_sptr
(new gr_file_meta_sink(itemsize, filename,
samp_rate, relative_rate,
type, complex,
+ max_segment_size,
extra_dict));
}
gr_file_meta_sink::gr_file_meta_sink(size_t itemsize, const char *filename,
double samp_rate, double relative_rate,
gr_file_types type, bool complex,
+ size_t max_segment_size,
const std::string &extra_dict)
: gr_sync_block("file_meta_sink",
gr_make_io_signature(1, 1, itemsize),
gr_make_io_signature(0, 0, 0)),
gr_file_sink_base(filename, true),
d_itemsize(itemsize), d_relative_rate(relative_rate),
- d_total_seg_size(0)
+ d_max_seg_size(max_segment_size), d_total_seg_size(0)
{
if(!open(filename))
throw std::runtime_error("file_meta_sink: can't open file\n");
@@ -77,11 +78,12 @@ gr_file_meta_sink::gr_file_meta_sink(size_t itemsize, const char *filename,
d_extra_size = pmt_serialize_str(d_extra).size();
d_header = pmt_make_dict();
+ d_header = pmt_dict_add(d_header, mp("version"), mp(METADATA_VERSION));
d_header = pmt_dict_add(d_header, mp("rx_rate"), mp(samp_rate));
d_header = pmt_dict_add(d_header, mp("rx_time"), timestamp);
d_header = pmt_dict_add(d_header, mp("type"), pmt_from_long(type));
d_header = pmt_dict_add(d_header, mp("cplx"), complex ? PMT_T : PMT_F);
- d_header = pmt_dict_add(d_header, mp("strt"), pmt_from_uint64(HEADER_SIZE+d_extra_size));
+ d_header = pmt_dict_add(d_header, mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size));
d_header = pmt_dict_add(d_header, mp("size"), pmt_from_uint64(0));
write_header(d_header, d_extra);
@@ -95,7 +97,7 @@ gr_file_meta_sink::write_header(pmt_t header, pmt_t extra)
std::string header_str = pmt_serialize_str(header);
std::string extra_str = pmt_serialize_str(extra);
- if((header_str.size() != HEADER_SIZE) && (extra_str.size() != d_extra_size))
+ if((header_str.size() != METADATA_HEADER_SIZE) && (extra_str.size() != d_extra_size))
throw std::runtime_error("file_meta_sink: header or extras is wrong size.\n");
size_t nwritten = 0;
@@ -144,31 +146,63 @@ gr_file_meta_sink::update_header(pmt_t key, pmt_t value)
}
}
+void
+gr_file_meta_sink::update_last_header()
+{
+ // Update the last header info with the number of samples this
+ // block represents.
+ size_t seg_size = d_itemsize*d_total_seg_size;
+ uint64_t loc = get_last_header_loc();
+ pmt_t s = pmt_from_uint64(seg_size);
+ //std::cerr << "Found Tag at: " << itr->offset*d_itemsize << std::endl;
+ //std::cerr << " last header starts at: " << loc << std::endl;
+ //std::cerr << " segment size is: " << seg_size << std::endl;
+ if(update_header(mp("size"), s)) {
+ fseek(d_fp, loc, SEEK_SET);
+ write_header(d_header, d_extra);
+ }
+}
+
+void
+gr_file_meta_sink::write_and_update()
+{
+ // New header, so set current size of chunk to 0 and start of chunk
+ // based on current index + header size.
+ uint64_t loc = get_last_header_loc();
+ pmt_t s = pmt_from_uint64(0);
+ size_t seg_size = d_itemsize*d_total_seg_size;
+ if(update_header(mp("size"), s)) {
+ // If we have multiple tags on the same offset, this makes
+ // sure we just overwrite the same header each time instead
+ // of creating a new header per tag.
+ uint64_t seg_start = loc;
+ if(seg_size != 0)
+ seg_start += METADATA_HEADER_SIZE + d_extra_size + seg_size + 1;
+ s = pmt_from_uint64(seg_start + METADATA_HEADER_SIZE + d_extra_size);
+ if(update_header(mp("strt"), s)) {
+ //std::cerr << "Adding new header" << std::endl;
+ //std::cerr << " new header start at: " << seg_start-METADATA_HEADER_SIZE << std::endl;
+ //std::cerr << " new seg start at: " << seg_start << std::endl;
+ fseek(d_fp, seg_start, SEEK_SET);
+ write_header(d_header, d_extra);
+ d_total_seg_size = 0;
+ }
+ }
+}
+
uint64_t
gr_file_meta_sink::get_last_header_loc()
{
uint64_t loc = 0;
pmt_t v = pmt_dict_ref(d_header, mp("strt"), PMT_NIL);
if(!pmt_eq(v, PMT_NIL))
- loc = pmt_to_uint64(v) - (HEADER_SIZE+d_extra_size);
+ loc = pmt_to_uint64(v) - (METADATA_HEADER_SIZE+d_extra_size);
return loc;
}
gr_file_meta_sink::~gr_file_meta_sink()
{
- // Replace the last header block with the final count of the number
- // of items.
- uint64_t loc = get_last_header_loc();
- uint64_t seg_size = nitems_read(0) * d_itemsize - d_total_seg_size;
- pmt_t s = pmt_from_uint64(seg_size);
- //std::cerr << "Destructor" << std::endl;
- //std::cerr << " location of last header: " << loc << std::endl;
- //std::cerr << " nitems_read: " << nitems_read(0)*d_itemsize << std::endl;
- //std::cerr << " Segment Size: " << seg_size << std::endl;
- if(update_header(mp("size"), s)) {
- fseek(d_fp, loc, SEEK_SET);
- write_header(d_header, d_extra);
- }
+ update_last_header();
}
int
@@ -188,7 +222,7 @@ gr_file_meta_sink::work(int noutput_items,
uint64_t end_N = abs_N + (uint64_t)(noutput_items);
std::vector<gr_tag_t> all_tags;
get_tags_in_range(all_tags, 0, abs_N, end_N);
-
+
std::vector<gr_tag_t>::iterator itr;
for(itr = all_tags.begin(); itr != all_tags.end(); itr++) {
// Special case where info is carried on the first tag, so we just
@@ -200,50 +234,27 @@ gr_file_meta_sink::work(int noutput_items,
}
}
else {
- // Update the last header info with the number of samples this
- // block represents.
- uint64_t loc = get_last_header_loc();
- uint64_t seg_size = itr->offset * d_itemsize - d_total_seg_size;
- pmt_t s = pmt_from_uint64(seg_size);
- //std::cerr << "Found Tag at: " << itr->offset*d_itemsize << std::endl;
- //std::cerr << " last header starts at: " << loc << std::endl;
- //std::cerr << " segment size is: " << seg_size << std::endl;
- if(update_header(mp("size"), s)) {
- fseek(d_fp, loc, SEEK_SET);
- write_header(d_header, d_extra);
- }
-
+ update_last_header();
if(update_header(itr->key, itr->value)) {
- // Otherwise, set current size of chunk to 0 and start of
- // chunk based on current index + header size.
- d_total_seg_size += seg_size;
- s = pmt_from_uint64(0);
- if(update_header(mp("size"), s)) {
- // If we have multiple tags on the same offset, this makes
- // sure we just overwrite the same header each time instead
- // of creating a new header per tag.
- uint64_t seg_start = loc;
- if(seg_size != 0)
- seg_start += HEADER_SIZE + d_extra_size + seg_size + 1;
- pmt_t s = pmt_from_uint64(seg_start + HEADER_SIZE + d_extra_size);
- if(update_header(mp("strt"), s)) {
- //std::cerr << "Adding new header" << std::endl;
- //std::cerr << " new header start at: " << seg_start-HEADER_SIZE << std::endl;
- //std::cerr << " new seg start at: " << seg_start << std::endl;
- fseek(d_fp, seg_start, SEEK_SET);
- write_header(d_header, d_extra);
- }
- }
+ write_and_update();
}
}
}
while(nwritten < noutput_items) {
- int count = fwrite(inbuf, d_itemsize, noutput_items - nwritten, d_fp);
+ size_t towrite = std::min(d_max_seg_size - d_total_seg_size,
+ (size_t)(noutput_items - nwritten));
+ int count = fwrite(inbuf, d_itemsize, towrite, d_fp);
if(count == 0) // FIXME add error handling
break;
nwritten += count;
inbuf += count * d_itemsize;
+
+ d_total_seg_size += count;
+ if(d_total_seg_size == d_max_seg_size) {
+ update_last_header();
+ write_and_update();
+ }
}
if(d_unbuffered)
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_sink.h b/gnuradio-core/src/lib/io/gr_file_meta_sink.h
index 9ba4878d1..f02c2c4ad 100644
--- a/gnuradio-core/src/lib/io/gr_file_meta_sink.h
+++ b/gnuradio-core/src/lib/io/gr_file_meta_sink.h
@@ -30,6 +30,9 @@
using namespace pmt;
+const char METADATA_VERSION = 0;
+const size_t METADATA_HEADER_SIZE = 134;
+
enum gr_file_types {
GR_FILE_BYTE=0,
GR_FILE_CHAR=0,
@@ -48,6 +51,7 @@ GR_CORE_API gr_file_meta_sink_sptr
gr_make_file_meta_sink(size_t itemsize, const char *filename,
double samp_rate=1, double relative_rate=1,
gr_file_types type=GR_FILE_FLOAT, bool complex=true,
+ size_t max_segment_size=1000000,
const std::string &extra_dict="");
/*!
@@ -86,6 +90,8 @@ class GR_CORE_API gr_file_meta_sink : public gr_sync_block, public gr_file_sink_
* rate tag to sink.
* \param type (gr_file_types): Data type (int, float, etc.)
* \param complex (bool): If data stream is complex
+ * \param max_segment_size (size_t): Length of a single segment
+ * before the header is repeated (in items).
* \param extra_dict (string): a serialized PMT dictionary of extra
* information. Currently not supported.
*/
@@ -93,12 +99,14 @@ class GR_CORE_API gr_file_meta_sink : public gr_sync_block, public gr_file_sink_
gr_make_file_meta_sink(size_t itemsize, const char *filename,
double samp_rate, double relative_rate,
gr_file_types type, bool complex,
+ size_t max_segment_size,
const std::string &extra_dict);
private:
size_t d_itemsize;
double d_relative_rate;
- uint64_t d_total_seg_size;
+ size_t d_max_seg_size;
+ size_t d_total_seg_size;
pmt_t d_header;
pmt_t d_extra;
size_t d_extra_size;
@@ -107,15 +115,20 @@ class GR_CORE_API gr_file_meta_sink : public gr_sync_block, public gr_file_sink_
gr_file_meta_sink(size_t itemsize, const char *filename,
double samp_rate=1, double relative_rate=1,
gr_file_types type=GR_FILE_FLOAT, bool complex=true,
+ size_t max_segment_size=1000000,
const std::string &extra_dict="");
void write_header(pmt_t header, pmt_t extra);
bool update_header(pmt_t key, pmt_t value);
+ void update_last_header();
+ void write_and_update();
uint64_t get_last_header_loc();
public:
~gr_file_meta_sink();
+ //FIXME: add setters/getters for properties.
+
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_sink.i b/gnuradio-core/src/lib/io/gr_file_meta_sink.i
index b58a519ce..6cced3f38 100644
--- a/gnuradio-core/src/lib/io/gr_file_meta_sink.i
+++ b/gnuradio-core/src/lib/io/gr_file_meta_sink.i
@@ -22,6 +22,9 @@
GR_SWIG_BLOCK_MAGIC(gr,file_meta_sink)
+const char METADATA_VERSION = 0;
+const size_t METADATA_HEADER_SIZE = 134;
+
enum gr_file_types {
GR_FILE_BYTE=0,
GR_FILE_CHAR=0,
@@ -37,6 +40,7 @@ gr_file_meta_sink_sptr
gr_make_file_meta_sink(size_t itemsize, const char *filename,
double samp_rate=1, double relative_rate=1,
gr_file_types type=GR_FILE_FLOAT, bool complex=true,
+ size_t max_segment_size=1000000,
const std::string & extra_dict="");
class gr_file_meta_sink : public gr_sync_block, public gr_file_sink_base
@@ -45,6 +49,7 @@ class gr_file_meta_sink : public gr_sync_block, public gr_file_sink_base
gr_file_meta_sink(size_t itemsize, const char *filename,
double samp_rate, double relative_rate,
gr_file_types type, bool complex,
+ size_t max_segment_size,
const std::string & extra_dict);
public:
diff --git a/gnuradio-core/src/python/gnuradio/parse_file_metadata.py b/gnuradio-core/src/python/gnuradio/parse_file_metadata.py
index c8a9fbde1..31ba5f7f0 100644
--- a/gnuradio-core/src/python/gnuradio/parse_file_metadata.py
+++ b/gnuradio-core/src/python/gnuradio/parse_file_metadata.py
@@ -32,7 +32,8 @@ strt Start of data (or size of header) in bytes
size Size of data in bytes
'''
-HEADER_LENGTH = 117
+HEADER_LENGTH = gr.METADATA_HEADER_SIZE
+
ftype_to_string = {gr.GR_FILE_BYTE: "bytes",
gr.GR_FILE_SHORT: "short",
gr.GR_FILE_INT: "int",
@@ -58,6 +59,16 @@ def parse_header(p, hdr_start, VERBOSE=False):
sys.stderr.write("Header is not a PMT dictionary: invalid or corrupt data file.\n")
sys.exit(1)
+ # GET FILE FORMAT VERSION NUMBER
+ if(gr.pmt_dict_has_key(p, gr.pmt_string_to_symbol("version"))):
+ r = gr.pmt_dict_ref(p, gr.pmt_string_to_symbol("version"), dump)
+ version = gr.pmt_to_long(r)
+ if(VERBOSE):
+ print "Version Number: {0}".format(version)
+ else:
+ sys.stderr.write("Could not find key 'sr': invalid or corrupt data file.\n")
+ sys.exit(1)
+
# EXTRACT SAMPLE RATE
if(gr.pmt_dict_has_key(p, gr.pmt_string_to_symbol("rx_rate"))):
r = gr.pmt_dict_ref(p, gr.pmt_string_to_symbol("rx_rate"), dump)