| /* |
| * The real io-stuff is in tarkin-io.c |
| * (this one has to be rewritten to write ogg streams ...) |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include "mem.h" |
| #include "tarkin.h" |
| #include "yuv.h" |
| |
| |
| #define N_FRAMES 1 |
| |
| |
| |
| TarkinStream * |
| tarkin_stream_new () |
| { |
| TarkinStream *s = (TarkinStream *) CALLOC (1, sizeof (TarkinStream)); |
| |
| if (!s) |
| return NULL; |
| memset (s, 0, sizeof (*s)); |
| |
| s->frames_per_buf = N_FRAMES; |
| |
| return s; |
| } |
| |
| |
| void |
| tarkin_stream_destroy (TarkinStream * s) |
| { |
| uint32_t i, j; |
| |
| if (!s) |
| return; |
| |
| for (i = 0; i < s->n_layers; i++) { |
| if (s->layer[i].waveletbuf) { |
| for (j = 0; j < s->layer[i].n_comp; j++) { |
| wavelet_3d_buf_destroy (s->layer[i].waveletbuf[j]); |
| FREE (s->layer[i].packet[j].data); |
| } |
| FREE (s->layer[i].waveletbuf); |
| FREE (s->layer[i].packet); |
| } |
| } |
| |
| if (s->layer) |
| FREE (s->layer); |
| |
| if (s->headers.header) |
| FREE (s->headers.header); |
| |
| if (s->headers.header1) |
| FREE (s->headers.header1); |
| |
| if (s->headers.header2) |
| FREE (s->headers.header2); |
| |
| |
| FREE (s); |
| } |
| |
| |
| int |
| tarkin_analysis_init (TarkinStream * s, TarkinInfo * ti, |
| TarkinError (*free_frame) (void *s, void *ptr), |
| TarkinError (*packet_out) (void *s, ogg_packet * ptr), void *user_ptr) |
| { |
| if ((!ti->inter.numerator) || (!ti->inter.denominator)) |
| return (-TARKIN_FAULT); |
| if ((!free_frame) || (!packet_out)) |
| return (-TARKIN_FAULT); |
| s->ti = ti; |
| s->free_frame = free_frame; |
| s->packet_out = packet_out; |
| s->user_ptr = user_ptr; |
| return (0); |
| } |
| |
| |
| extern int |
| tarkin_analysis_add_layer (TarkinStream * s, TarkinVideoLayerDesc * tvld) |
| { |
| int i; |
| TarkinVideoLayer *layer; |
| |
| if (s->n_layers) { |
| s->layer = REALLOC (s->layer, (s->n_layers + 1) * sizeof (*s->layer)); |
| } else { |
| s->layer = MALLOC (sizeof (*s->layer)); |
| } |
| layer = s->layer + s->n_layers; |
| memset (layer, 0, sizeof (*s->layer)); |
| memcpy (&layer->desc, tvld, sizeof (TarkinVideoLayerDesc)); |
| |
| s->n_layers++; |
| s->ti->n_layers = s->n_layers; |
| s->ti->layer = s->layer; |
| |
| switch (layer->desc.format) { |
| case TARKIN_GRAYSCALE: |
| layer->n_comp = 1; |
| layer->color_fwd_xform = grayscale_to_y; |
| layer->color_inv_xform = y_to_grayscale; |
| break; |
| case TARKIN_RGB24: |
| layer->n_comp = 3; |
| layer->color_fwd_xform = rgb24_to_yuv; |
| layer->color_inv_xform = yuv_to_rgb24; |
| break; |
| case TARKIN_RGB32: |
| layer->n_comp = 3; |
| layer->color_fwd_xform = rgb32_to_yuv; |
| layer->color_inv_xform = yuv_to_rgb32; |
| break; |
| case TARKIN_RGBA: |
| layer->n_comp = 4; |
| layer->color_fwd_xform = rgba_to_yuv; |
| layer->color_inv_xform = yuv_to_rgba; |
| break; |
| default: |
| return -TARKIN_INVALID_COLOR_FORMAT; |
| }; |
| |
| #ifdef DBG_OGG |
| printf ("dbg_ogg:add_layer %d with %d components\n", |
| s->n_layers, layer->n_comp); |
| #endif |
| |
| layer->waveletbuf = (Wavelet3DBuf **) CALLOC (layer->n_comp, |
| sizeof (Wavelet3DBuf *)); |
| |
| layer->packet = MALLOC (layer->n_comp * sizeof (*layer->packet)); |
| memset (layer->packet, 0, layer->n_comp * sizeof (*layer->packet)); |
| |
| for (i = 0; i < layer->n_comp; i++) { |
| layer->waveletbuf[i] = wavelet_3d_buf_new (layer->desc.width, |
| layer->desc.height, layer->desc.frames_per_buf); |
| layer->packet[i].data = MALLOC (layer->desc.bitstream_len); |
| layer->packet[i].storage = layer->desc.bitstream_len; |
| } |
| /* |
| max_bitstream_len += layer->desc.bitstream_len |
| + 2 * 10 * sizeof(uint32_t) * layer->n_comp; |
| */ |
| return (TARKIN_OK); |
| } |
| |
| TarkinError |
| _analysis_packetout (TarkinStream * s, uint32_t layer_id, uint32_t comp) |
| { |
| ogg_packet op; |
| oggpack_buffer opb; |
| uint8_t *data; |
| uint32_t data_len; |
| int i; |
| |
| data = s->layer[layer_id].packet[comp].data; |
| data_len = s->layer[layer_id].packet[comp].data_len; |
| |
| oggpack_writeinit (&opb); |
| oggpack_write (&opb, 0, 8); /* No feature flags for now */ |
| oggpack_write (&opb, layer_id, 12); |
| oggpack_write (&opb, comp, 12); |
| for (i = 0; i < data_len; i++) |
| oggpack_write (&opb, *(data + i), 8); |
| |
| op.b_o_s = 0; |
| op.e_o_s = data_len ? 0 : 1; |
| op.granulepos = 0; |
| op.bytes = oggpack_bytes (&opb) + 4; |
| op.packet = opb.buffer; |
| #ifdef DBG_OGG |
| printf ("dbg_ogg: writing packet layer %d, comp %d, data_len %d %s\n", |
| layer_id, comp, data_len, op.e_o_s ? "eos" : ""); |
| #endif |
| s->layer[layer_id].packet[comp].data_len = 0; /* so direct call => eos */ |
| return (s->packet_out (s, &op)); |
| } |
| |
| void |
| _stream_flush (TarkinStream * s) |
| { |
| uint32_t i, j; |
| |
| s->current_frame_in_buf = 0; |
| |
| for (i = 0; i < s->n_layers; i++) { |
| TarkinVideoLayer *layer = &s->layer[i]; |
| |
| for (j = 0; j < layer->n_comp; j++) { |
| uint32_t comp_bitstream_len; |
| TarkinPacket *packet = layer->packet + j; |
| |
| /** |
| * implicit 6:1:1 subsampling |
| */ |
| if (j == 0) |
| comp_bitstream_len = |
| 6 * layer->desc.bitstream_len / (layer->n_comp + 5); |
| else |
| comp_bitstream_len = layer->desc.bitstream_len / (layer->n_comp + 5); |
| |
| if (packet->storage < comp_bitstream_len) { |
| packet->storage = comp_bitstream_len; |
| packet->data = REALLOC (packet->data, comp_bitstream_len); |
| } |
| |
| wavelet_3d_buf_dump ("color-%d-%03d.pgm", |
| s->current_frame, j, layer->waveletbuf[j], j == 0 ? 0 : 128); |
| |
| wavelet_3d_buf_fwd_xform (layer->waveletbuf[j], |
| layer->desc.a_moments, layer->desc.s_moments); |
| |
| wavelet_3d_buf_dump ("coeff-%d-%03d.pgm", |
| s->current_frame, j, layer->waveletbuf[j], 128); |
| |
| packet->data_len = wavelet_3d_buf_encode_coeff (layer->waveletbuf[j], |
| packet->data, comp_bitstream_len); |
| |
| _analysis_packetout (s, i, j); |
| } |
| } |
| } |
| |
| |
| uint32_t |
| tarkin_analysis_framein (TarkinStream * s, uint8_t * frame, |
| uint32_t layer_id, TarkinTime * date) |
| { |
| TarkinVideoLayer *layer; |
| |
| if (!frame) |
| return (_analysis_packetout (s, 0, 0)); /* eos */ |
| if ((layer_id >= s->n_layers) || (date->denominator == 0)) |
| return (TARKIN_FAULT); |
| |
| layer = s->layer + layer_id; |
| layer->color_fwd_xform (frame, layer->waveletbuf, s->current_frame_in_buf); |
| /* We don't use this feature for now, neither date... */ |
| s->free_frame (s, frame); |
| |
| s->current_frame_in_buf++; |
| |
| if (s->current_frame_in_buf == s->frames_per_buf) |
| _stream_flush (s); |
| |
| #ifdef DBG_OGG |
| printf ("dbg_ogg: framein at pos %d/%d, n? %d,%d on layer %d\n", |
| date->numerator, date->denominator, |
| layer->frameno, s->current_frame, layer_id); |
| #endif |
| |
| layer->frameno++; |
| return (++s->current_frame); |
| } |
| |
| |
| |
| |
| /** |
| * tarkin_stream_read_header() is now info.c:_tarkin_unpack_layer_desc() |
| */ |
| |
| |
| |
| TarkinError |
| tarkin_stream_get_layer_desc (TarkinStream * s, |
| uint32_t layer_id, TarkinVideoLayerDesc * desc) |
| { |
| if (layer_id > s->n_layers - 1) |
| return -TARKIN_INVALID_LAYER; |
| |
| memcpy (desc, &(s->layer[layer_id].desc), sizeof (TarkinVideoLayerDesc)); |
| |
| return TARKIN_OK; |
| } |
| |
| TarkinError |
| tarkin_synthesis_init (TarkinStream * s, TarkinInfo * ti) |
| { |
| s->ti = ti; |
| s->layer = ti->layer; /* It was malloc()ed by headerin() */ |
| s->n_layers = ti->n_layers; |
| return (TARKIN_OK); |
| } |
| |
| TarkinError |
| tarkin_synthesis_packetin (TarkinStream * s, ogg_packet * op) |
| { |
| uint32_t i, layer_id, comp, data_len; |
| uint32_t flags, junk; |
| int nread; |
| oggpack_buffer opb; |
| TarkinPacket *packet; |
| |
| #ifdef DBG_OGG |
| printf ("dbg_ogg: Reading packet n? %lld, granulepos %lld, len %ld, %s%s\n", |
| op->packetno, op->granulepos, op->bytes, |
| op->b_o_s ? "b_o_s" : "", op->e_o_s ? "e_o_s" : ""); |
| #endif |
| oggpack_readinit (&opb, op->packet, op->bytes); |
| flags = oggpack_read (&opb, 8); |
| layer_id = oggpack_read (&opb, 12); /* Theses are required for */ |
| comp = oggpack_read (&opb, 12); /* data hole handling (or maybe |
| * packetno would be enough ?) */ |
| nread = 4; |
| |
| if (flags) { /* This is void "infinite future features" feature ;) */ |
| if (flags & 1 << 7) { |
| junk = flags; |
| while (junk & 1 << 7) |
| junk = oggpack_read (&opb, 8); /* allow for many future flags |
| that must be correctly ordonned. */ |
| } |
| /* This shows how to get a feature's data: |
| if (flags & TARKIN_FLAGS_EXAMPLE){ |
| tp->example = oggpack_read(&opb,32); |
| junk = tp->example & 3<<30; |
| tp->example &= 0x4fffffff; |
| } |
| */ |
| for (junk = 1 << 31; junk & 1 << 31;) /* and many future data */ |
| while ((junk = oggpack_read (&opb, 32)) & 1 << 30); |
| /* That is, feature data comes in 30 bit chunks. We also have |
| * 31 potentially useful bits in last chunk. */ |
| } |
| |
| nread = (opb.ptr - opb.buffer); |
| data_len = op->bytes - nread; |
| |
| #ifdef DBG_OGG |
| printf (" layer_id %d, comp %d, meta-data %dB, w3d data %dB.\n", |
| layer_id, comp, nread, data_len); |
| #endif |
| |
| /* We now have for shure our data. */ |
| packet = &s->layer[layer_id].packet[comp]; |
| if (packet->data_len) |
| return (-TARKIN_UNUSED); /* Previous data wasn't used */ |
| |
| if (packet->storage < data_len) { |
| packet->storage = data_len + 255; |
| packet->data = REALLOC (packet->data, packet->storage); |
| } |
| |
| for (i = 0; i < data_len; i++) |
| packet->data[i] = oggpack_read (&opb, 8); |
| |
| packet->data_len = data_len; |
| |
| return (TARKIN_OK); |
| } |
| |
| TarkinError |
| tarkin_synthesis_frameout (TarkinStream * s, |
| uint8_t ** frame, uint32_t layer_id, TarkinTime * date) |
| { |
| int j; |
| TarkinVideoLayer *layer = &s->layer[layer_id]; |
| |
| if (s->current_frame_in_buf == 0) { |
| *frame = MALLOC (layer->desc.width * layer->desc.height * layer->n_comp); |
| for (j = 0; j < layer->n_comp; j++) { |
| TarkinPacket *packet = layer->packet + j; |
| |
| if (packet->data_len == 0) |
| goto err_out; |
| |
| wavelet_3d_buf_decode_coeff (layer->waveletbuf[j], packet->data, |
| packet->data_len); |
| |
| wavelet_3d_buf_dump ("rcoeff-%d-%03d.pgm", |
| s->current_frame, j, layer->waveletbuf[j], 128); |
| |
| wavelet_3d_buf_inv_xform (layer->waveletbuf[j], |
| layer->desc.a_moments, layer->desc.s_moments); |
| |
| wavelet_3d_buf_dump ("rcolor-%d-%03d.pgm", |
| s->current_frame, j, layer->waveletbuf[j], j == 0 ? 0 : 128); |
| } |
| |
| /* We did successfylly read a block from this layer, acknowledge it. */ |
| for (j = 0; j < layer->n_comp; j++) |
| layer->packet[j].data_len = 0; |
| } |
| |
| layer->color_inv_xform (layer->waveletbuf, *frame, s->current_frame_in_buf); |
| s->current_frame_in_buf++; |
| s->current_frame++; |
| |
| if (s->current_frame_in_buf == s->frames_per_buf) |
| s->current_frame_in_buf = 0; |
| |
| date->numerator = layer->frameno * s->ti->inter.numerator; |
| date->denominator = s->ti->inter.denominator; |
| #ifdef DBG_OGG |
| printf ("dbg_ogg: outputting frame pos %d/%d from layer %d.\n", |
| date->numerator, date->denominator, layer_id); |
| #endif |
| layer->frameno++; |
| return (TARKIN_OK); |
| err_out: |
| FREE (*frame); |
| return (TARKIN_NEED_MORE); |
| } |
| |
| int |
| tarkin_synthesis_freeframe (TarkinStream * s, uint8_t * frame) |
| { |
| FREE (frame); |
| |
| return (TARKIN_OK); |
| } |