| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 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 | 
| OLD | NEW | 
|---|