FFmpeg
mlz.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Umair Khan <omerjerk@gmail.com>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include "mlz.h"
22 
24 {
25  mlz->dict = av_mallocz(TABLE_SIZE * sizeof(*mlz->dict));
26  if (!mlz->dict)
27  return AVERROR(ENOMEM);
28 
29  mlz->flush_code = FLUSH_CODE;
32  mlz->bump_code = (DIC_INDEX_INIT - 1);
33  mlz->next_code = FIRST_CODE;
34  mlz->freeze_flag = 0;
35  mlz->context = context;
36 
37  return 0;
38 }
39 
41  MLZDict *dict = mlz->dict;
42  int i;
43  for ( i = 0; i < TABLE_SIZE; i++ ) {
44  dict[i].string_code = CODE_UNSET;
45  dict[i].parent_code = CODE_UNSET;
46  dict[i].match_len = 0;
47  }
49  mlz->dic_code_bit = CODE_BIT_INIT; // DicCodeBitInit;
50  mlz->bump_code = mlz->current_dic_index_max - 1;
51  mlz->next_code = FIRST_CODE;
52  mlz->freeze_flag = 0;
53 }
54 
55 static void set_new_entry_dict(MLZDict* dict, int string_code, int parent_code, int char_code) {
56  dict[string_code].parent_code = parent_code;
57  dict[string_code].string_code = string_code;
58  dict[string_code].char_code = char_code;
59  if (parent_code < FIRST_CODE) {
60  dict[string_code].match_len = 2;
61  } else {
62  dict[string_code].match_len = (dict[parent_code].match_len) + 1;
63  }
64 }
65 
66 static int decode_string(MLZ* mlz, unsigned char *buff, int string_code, int *first_char_code, unsigned long bufsize) {
67  MLZDict* dict = mlz->dict;
68  unsigned long count, offset;
69  int current_code, parent_code, tmp_code;
70 
71  count = 0;
72  current_code = string_code;
73  *first_char_code = CODE_UNSET;
74 
75  while (count < bufsize) {
76  switch (current_code) {
77  case CODE_UNSET:
78  return count;
79  break;
80  default:
81  if (current_code < FIRST_CODE) {
82  *first_char_code = current_code;
83  buff[0] = current_code;
84  count++;
85  return count;
86  } else {
87  offset = dict[current_code].match_len - 1;
88  tmp_code = dict[current_code].char_code;
89  if (offset >= bufsize) {
90  av_log(mlz->context, AV_LOG_ERROR, "MLZ offset error.\n");
91  return count;
92  }
93  buff[offset] = tmp_code;
94  count++;
95  }
96  current_code = dict[current_code].parent_code;
97  if ((current_code < 0) || (current_code > (DIC_INDEX_MAX - 1))) {
98  av_log(mlz->context, AV_LOG_ERROR, "MLZ dic index error.\n");
99  return count;
100  }
101  if (current_code > FIRST_CODE) {
102  parent_code = dict[current_code].parent_code;
103  offset = (dict[current_code].match_len) - 1;
104  if (parent_code < 0 || parent_code > DIC_INDEX_MAX-1) {
105  av_log(mlz->context, AV_LOG_ERROR, "MLZ dic index error.\n");
106  return count;
107  }
108  if (( offset > (DIC_INDEX_MAX - 1))) {
109  av_log(mlz->context, AV_LOG_ERROR, "MLZ dic offset error.\n");
110  return count;
111  }
112  }
113  break;
114  }
115  }
116  return count;
117 }
118 
119 static int input_code(GetBitContext* gb, int len) {
120  int tmp_code = 0;
121  int i;
122  for (i = 0; i < len; ++i) {
123  tmp_code |= get_bits1(gb) << i;
124  }
125  return tmp_code;
126 }
127 
128 int ff_mlz_decompression(MLZ* mlz, GetBitContext* gb, int size, unsigned char *buff) {
129  MLZDict *dict = mlz->dict;
130  unsigned long output_chars;
131  int string_code, last_string_code, char_code;
132 
133  string_code = 0;
134  char_code = -1;
135  last_string_code = -1;
136  output_chars = 0;
137 
138  while (output_chars < size) {
139  string_code = input_code(gb, mlz->dic_code_bit);
140  switch (string_code) {
141  case FLUSH_CODE:
142  case MAX_CODE:
143  ff_mlz_flush_dict(mlz);
144  char_code = -1;
145  last_string_code = -1;
146  break;
147  case FREEZE_CODE:
148  mlz->freeze_flag = 1;
149  break;
150  default:
151  if (string_code > mlz->current_dic_index_max) {
152  av_log(mlz->context, AV_LOG_ERROR, "String code %d exceeds maximum value of %d.\n", string_code, mlz->current_dic_index_max);
153  return output_chars;
154  }
155  if (string_code == (int) mlz->bump_code) {
156  ++mlz->dic_code_bit;
157  mlz->current_dic_index_max *= 2;
158  mlz->bump_code = mlz->current_dic_index_max - 1;
159  } else {
160  if (string_code >= mlz->next_code) {
161  int ret = decode_string(mlz, &buff[output_chars], last_string_code, &char_code, size - output_chars);
162  if (ret < 0 || ret > size - output_chars) {
163  av_log(mlz->context, AV_LOG_ERROR, "output chars overflow\n");
164  return output_chars;
165  }
166  output_chars += ret;
167  ret = decode_string(mlz, &buff[output_chars], char_code, &char_code, size - output_chars);
168  if (ret < 0 || ret > size - output_chars) {
169  av_log(mlz->context, AV_LOG_ERROR, "output chars overflow\n");
170  return output_chars;
171  }
172  output_chars += ret;
173  set_new_entry_dict(dict, mlz->next_code, last_string_code, char_code);
174  if (mlz->next_code >= TABLE_SIZE - 1) {
175  av_log(mlz->context, AV_LOG_ERROR, "Too many MLZ codes\n");
176  return output_chars;
177  }
178  mlz->next_code++;
179  } else {
180  int ret = decode_string(mlz, &buff[output_chars], string_code, &char_code, size - output_chars);
181  if (ret < 0 || ret > size - output_chars) {
182  av_log(mlz->context, AV_LOG_ERROR, "output chars overflow\n");
183  return output_chars;
184  }
185  output_chars += ret;
186  if (output_chars <= size && !mlz->freeze_flag) {
187  if (last_string_code != -1) {
188  set_new_entry_dict(dict, mlz->next_code, last_string_code, char_code);
189  if (mlz->next_code >= TABLE_SIZE - 1) {
190  av_log(mlz->context, AV_LOG_ERROR, "Too many MLZ codes\n");
191  return output_chars;
192  }
193  mlz->next_code++;
194  }
195  } else {
196  break;
197  }
198  }
199  last_string_code = string_code;
200  }
201  break;
202  }
203  }
204  return output_chars;
205 }
MLZDict::string_code
int string_code
Definition: mlz.h:39
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
ff_mlz_flush_dict
av_cold void ff_mlz_flush_dict(MLZ *mlz)
Flush the dictionary.
Definition: mlz.c:40
set_new_entry_dict
static void set_new_entry_dict(MLZDict *dict, int string_code, int parent_code, int char_code)
Definition: mlz.c:55
FREEZE_CODE
#define FREEZE_CODE
Definition: mlz.h:31
DIC_INDEX_INIT
#define DIC_INDEX_INIT
Definition: mlz.h:28
DIC_INDEX_MAX
#define DIC_INDEX_MAX
Definition: mlz.h:29
MLZ
MLZ data strucure.
Definition: mlz.h:47
GetBitContext
Definition: get_bits.h:61
MLZDict::parent_code
int parent_code
Definition: mlz.h:40
MLZDict::char_code
int char_code
Definition: mlz.h:41
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
MLZ::freeze_flag
int freeze_flag
Definition: mlz.h:53
MLZ::context
void * context
Definition: mlz.h:55
MLZ::current_dic_index_max
int current_dic_index_max
Definition: mlz.h:49
decode_string
static int decode_string(MLZ *mlz, unsigned char *buff, int string_code, int *first_char_code, unsigned long bufsize)
Definition: mlz.c:66
mlz.h
context
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option keep it simple and lowercase description are in without and describe what they for example set the foo of the bar offset is the offset of the field in your context
Definition: writing_filters.txt:91
get_bits1
static unsigned int get_bits1(GetBitContext *s)
Definition: get_bits.h:498
MLZ::next_code
int next_code
Definition: mlz.h:52
MLZDict
Dictionary structure for mlz decompression.
Definition: mlz.h:38
FIRST_CODE
#define FIRST_CODE
Definition: mlz.h:32
size
int size
Definition: twinvq_data.h:10344
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
MLZDict::match_len
int match_len
Definition: mlz.h:42
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
CODE_BIT_INIT
#define CODE_BIT_INIT
Definition: mlz.h:27
FLUSH_CODE
#define FLUSH_CODE
Definition: mlz.h:30
MLZ::dic_code_bit
int dic_code_bit
Definition: mlz.h:48
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:264
len
int len
Definition: vorbis_enc_data.h:426
TABLE_SIZE
#define TABLE_SIZE
Definition: mlz.h:34
ret
ret
Definition: filter_design.txt:187
MLZ::dict
MLZDict * dict
Definition: mlz.h:54
ff_mlz_decompression
int ff_mlz_decompression(MLZ *mlz, GetBitContext *gb, int size, unsigned char *buff)
Run mlz decompression on the next size bits and the output will be stored in buff.
Definition: mlz.c:128
MLZ::bump_code
unsigned int bump_code
Definition: mlz.h:50
CODE_UNSET
#define CODE_UNSET
Definition: mlz.h:26
ff_mlz_init_dict
av_cold int ff_mlz_init_dict(void *context, MLZ *mlz)
Initialize the dictionary.
Definition: mlz.c:23
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
MAX_CODE
#define MAX_CODE
Definition: mlz.h:33
MLZ::flush_code
unsigned int flush_code
Definition: mlz.h:51
input_code
static int input_code(GetBitContext *gb, int len)
Definition: mlz.c:119