Home | History | Annotate | Download | only in examples
      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