1 @TEMPLATE decoder_tmpl.c 2 Decode With Partial Drops Example 3 ========================= 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION 5 This is an example utility which drops a series of frames (or parts of frames), 6 as specified on the command line. This is useful for observing the error 7 recovery features of the codec. 8 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION 9 10 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES 11 #include <time.h> 12 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES 13 14 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS 15 struct parsed_header 16 { 17 char key_frame; 18 int version; 19 char show_frame; 20 int first_part_size; 21 }; 22 23 int next_packet(struct parsed_header* hdr, int pos, int length, int mtu) 24 { 25 int size = 0; 26 int remaining = length - pos; 27 /* Uncompressed part is 3 bytes for P frames and 10 bytes for I frames */ 28 int uncomp_part_size = (hdr->key_frame ? 10 : 3); 29 /* number of bytes yet to send from header and the first partition */ 30 int remainFirst = uncomp_part_size + hdr->first_part_size - pos; 31 if (remainFirst > 0) 32 { 33 if (remainFirst <= mtu) 34 { 35 size = remainFirst; 36 } 37 else 38 { 39 size = mtu; 40 } 41 42 return size; 43 } 44 45 /* second partition; just slot it up according to MTU */ 46 if (remaining <= mtu) 47 { 48 size = remaining; 49 return size; 50 } 51 return mtu; 52 } 53 54 void throw_packets(unsigned char* frame, int* size, int loss_rate, 55 int* thrown, int* kept) 56 { 57 unsigned char loss_frame[256*1024]; 58 int pkg_size = 1; 59 int pos = 0; 60 int loss_pos = 0; 61 struct parsed_header hdr; 62 unsigned int tmp; 63 int mtu = 1500; 64 65 if (*size < 3) 66 { 67 return; 68 } 69 putc('|', stdout); 70 /* parse uncompressed 3 bytes */ 71 tmp = (frame[2] << 16) | (frame[1] << 8) | frame[0]; 72 hdr.key_frame = !(tmp & 0x1); /* inverse logic */ 73 hdr.version = (tmp >> 1) & 0x7; 74 hdr.show_frame = (tmp >> 4) & 0x1; 75 hdr.first_part_size = (tmp >> 5) & 0x7FFFF; 76 77 /* don't drop key frames */ 78 if (hdr.key_frame) 79 { 80 int i; 81 *kept = *size/mtu + ((*size % mtu > 0) ? 1 : 0); /* approximate */ 82 for (i=0; i < *kept; i++) 83 putc('.', stdout); 84 return; 85 } 86 87 while ((pkg_size = next_packet(&hdr, pos, *size, mtu)) > 0) 88 { 89 int loss_event = ((rand() + 1.0)/(RAND_MAX + 1.0) < loss_rate/100.0); 90 if (*thrown == 0 && !loss_event) 91 { 92 memcpy(loss_frame + loss_pos, frame + pos, pkg_size); 93 loss_pos += pkg_size; 94 (*kept)++; 95 putc('.', stdout); 96 } 97 else 98 { 99 (*thrown)++; 100 putc('X', stdout); 101 } 102 pos += pkg_size; 103 } 104 memcpy(frame, loss_frame, loss_pos); 105 memset(frame + loss_pos, 0, *size - loss_pos); 106 *size = loss_pos; 107 } 108 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS 109 110 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT 111 /* Initialize codec */ 112 flags = VPX_CODEC_USE_ERROR_CONCEALMENT; 113 res = vpx_codec_dec_init(&codec, interface, &dec_cfg, flags); 114 if(res) 115 die_codec(&codec, "Failed to initialize decoder"); 116 117 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT 118 119 Usage 120 ----- 121 This example adds a single argument to the `simple_decoder` example, 122 which specifies the range or pattern of frames to drop. The parameter is 123 parsed as follows: 124 125 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE 126 if(argc < 4 || argc > 6) 127 die("Usage: %s <infile> <outfile> [-t <num threads>] <N-M|N/M|L,S>\n", 128 argv[0]); 129 { 130 char *nptr; 131 int arg_num = 3; 132 if (argc == 6 && strncmp(argv[arg_num++], "-t", 2) == 0) 133 dec_cfg.threads = strtol(argv[arg_num++], NULL, 0); 134 n = strtol(argv[arg_num], &nptr, 0); 135 mode = (*nptr == '\0' || *nptr == ',') ? 2 : (*nptr == '-') ? 1 : 0; 136 137 m = strtol(nptr+1, NULL, 0); 138 if((!n && !m) || (*nptr != '-' && *nptr != '/' && 139 *nptr != '\0' && *nptr != ',')) 140 die("Couldn't parse pattern %s\n", argv[3]); 141 } 142 seed = (m > 0) ? m : (unsigned int)time(NULL); 143 srand(seed);thrown_frame = 0; 144 printf("Seed: %u\n", seed); 145 printf("Threads: %d\n", dec_cfg.threads); 146 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE 147 148 149 Dropping A Range Of Frames 150 -------------------------- 151 To drop a range of frames, specify the starting frame and the ending 152 frame to drop, separated by a dash. The following command will drop 153 frames 5 through 10 (base 1). 154 155 $ ./decode_with_partial_drops in.ivf out.i420 5-10 156 157 158 Dropping A Pattern Of Frames 159 ---------------------------- 160 To drop a pattern of frames, specify the number of frames to drop and 161 the number of frames after which to repeat the pattern, separated by 162 a forward-slash. The following command will drop 3 of 7 frames. 163 Specifically, it will decode 4 frames, then drop 3 frames, and then 164 repeat. 165 166 $ ./decode_with_partial_drops in.ivf out.i420 3/7 167 168 Dropping Random Parts Of Frames 169 ------------------------------- 170 A third argument tuple is available to split the frame into 1500 bytes pieces 171 and randomly drop pieces rather than frames. The frame will be split at 172 partition boundaries where possible. The following example will seed the RNG 173 with the seed 123 and drop approximately 5% of the pieces. Pieces which 174 are depending on an already dropped piece will also be dropped. 175 176 $ ./decode_with_partial_drops in.ivf out.i420 5,123 177 178 179 Extra Variables 180 --------------- 181 This example maintains the pattern passed on the command line in the 182 `n`, `m`, and `is_range` variables: 183 184 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS 185 int n, m, mode; 186 unsigned int seed; 187 int thrown=0, kept=0; 188 int thrown_frame=0, kept_frame=0; 189 vpx_codec_dec_cfg_t dec_cfg = {0}; 190 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS 191 192 193 Making The Drop Decision 194 ------------------------ 195 The example decides whether to drop the frame based on the current 196 frame number, immediately before decoding the frame. 197 198 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE 199 /* Decide whether to throw parts of the frame or the whole frame 200 depending on the drop mode */ 201 thrown_frame = 0; 202 kept_frame = 0; 203 switch (mode) 204 { 205 case 0: 206 if (m - (frame_cnt-1)%m <= n) 207 { 208 frame_sz = 0; 209 } 210 break; 211 case 1: 212 if (frame_cnt >= n && frame_cnt <= m) 213 { 214 frame_sz = 0; 215 } 216 break; 217 case 2: 218 throw_packets(frame, &frame_sz, n, &thrown_frame, &kept_frame); 219 break; 220 default: break; 221 } 222 if (mode < 2) 223 { 224 if (frame_sz == 0) 225 { 226 putc('X', stdout); 227 thrown_frame++; 228 } 229 else 230 { 231 putc('.', stdout); 232 kept_frame++; 233 } 234 } 235 thrown += thrown_frame; 236 kept += kept_frame; 237 fflush(stdout); 238 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE 239