source: SHVCSoftware/branches/SHM-dev/source/App/utils/ExtractAddLS/ExtractAddLS.c @ 1201

Last change on this file since 1201 was 1023, checked in by interdigital, 10 years ago
  1. add code to support base layer bitstream extraction
  2. keep VPS for rewriting process so the output bitstream can be decoded by HM
  • Property svn:eol-style set to native
File size: 12.1 KB
Line 
1/* The copyright in this software is being made available under the BSD
2* License, included below. This software may be subject to other third party
3* and contributor rights, including patent rights, and no such rights are
4* granted under this license.
5*
6* Copyright (c) 2010-2014, ITU/ISO/IEC
7* All rights reserved.
8*
9* Redistribution and use in source and binary forms, with or without
10* modification, are permitted provided that the following conditions are met:
11*
12*  * Redistributions of source code must retain the above copyright notice,
13*    this list of conditions and the following disclaimer.
14*  * Redistributions in binary form must reproduce the above copyright notice,
15*    this list of conditions and the following disclaimer in the documentation
16*    and/or other materials provided with the distribution.
17*  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
18*    be used to endorse or promote products derived from this software without
19*    specific prior written permission.
20*
21* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31* THE POSSIBILITY OF SUCH DAMAGE.
32*/
33
34#include <stdlib.h>
35#include <stdio.h>
36#include <string.h>
37
38
39enum NalUnitType
40{
41  NAL_UNIT_CODED_SLICE_TRAIL_N = 0,
42  NAL_UNIT_CODED_SLICE_TRAIL_R,
43
44  NAL_UNIT_CODED_SLICE_TSA_N,
45  NAL_UNIT_CODED_SLICE_TSA_R,
46
47  NAL_UNIT_CODED_SLICE_STSA_N,
48  NAL_UNIT_CODED_SLICE_STSA_R,
49
50  NAL_UNIT_CODED_SLICE_RADL_N,
51  NAL_UNIT_CODED_SLICE_RADL_R,
52
53  NAL_UNIT_CODED_SLICE_RASL_N,
54  NAL_UNIT_CODED_SLICE_RASL_R,
55
56  NAL_UNIT_RESERVED_VCL_N10,
57  NAL_UNIT_RESERVED_VCL_R11,
58  NAL_UNIT_RESERVED_VCL_N12,
59  NAL_UNIT_RESERVED_VCL_R13,
60  NAL_UNIT_RESERVED_VCL_N14,
61  NAL_UNIT_RESERVED_VCL_R15,
62
63  NAL_UNIT_CODED_SLICE_BLA_W_LP,
64  NAL_UNIT_CODED_SLICE_BLA_W_RADL,
65  NAL_UNIT_CODED_SLICE_BLA_N_LP,
66  NAL_UNIT_CODED_SLICE_IDR_W_RADL,
67  NAL_UNIT_CODED_SLICE_IDR_N_LP,
68  NAL_UNIT_CODED_SLICE_CRA,
69  NAL_UNIT_RESERVED_IRAP_VCL22,
70  NAL_UNIT_RESERVED_IRAP_VCL23,
71
72  NAL_UNIT_RESERVED_VCL24,
73  NAL_UNIT_RESERVED_VCL25,
74  NAL_UNIT_RESERVED_VCL26,
75  NAL_UNIT_RESERVED_VCL27,
76  NAL_UNIT_RESERVED_VCL28,
77  NAL_UNIT_RESERVED_VCL29,
78  NAL_UNIT_RESERVED_VCL30,
79  NAL_UNIT_RESERVED_VCL31,
80
81  NAL_UNIT_VPS,
82  NAL_UNIT_SPS,
83  NAL_UNIT_PPS,
84  NAL_UNIT_ACCESS_UNIT_DELIMITER,
85  NAL_UNIT_EOS,
86  NAL_UNIT_EOB,
87  NAL_UNIT_FILLER_DATA,
88  NAL_UNIT_PREFIX_SEI,
89  NAL_UNIT_SUFFIX_SEI,
90  NAL_UNIT_RESERVED_NVCL41,
91  NAL_UNIT_RESERVED_NVCL42,
92  NAL_UNIT_RESERVED_NVCL43,
93  NAL_UNIT_RESERVED_NVCL44,
94  NAL_UNIT_RESERVED_NVCL45,
95  NAL_UNIT_RESERVED_NVCL46,
96  NAL_UNIT_RESERVED_NVCL47,
97  NAL_UNIT_UNSPECIFIED_48,
98  NAL_UNIT_UNSPECIFIED_49,
99  NAL_UNIT_UNSPECIFIED_50,
100  NAL_UNIT_UNSPECIFIED_51,
101  NAL_UNIT_UNSPECIFIED_52,
102  NAL_UNIT_UNSPECIFIED_53,
103  NAL_UNIT_UNSPECIFIED_54,
104  NAL_UNIT_UNSPECIFIED_55,
105  NAL_UNIT_UNSPECIFIED_56,
106  NAL_UNIT_UNSPECIFIED_57,
107  NAL_UNIT_UNSPECIFIED_58,
108  NAL_UNIT_UNSPECIFIED_59,
109  NAL_UNIT_UNSPECIFIED_60,
110  NAL_UNIT_UNSPECIFIED_61,
111  NAL_UNIT_UNSPECIFIED_62,
112  NAL_UNIT_UNSPECIFIED_63,
113  NAL_UNIT_INVALID,
114};
115
116char *nalUnitNames[] =
117{
118  "NAL_UNIT_CODED_SLICE_TRAIL_N",
119  "NAL_UNIT_CODED_SLICE_TRAIL_R",
120
121  "NAL_UNIT_CODED_SLICE_TSA_N",
122  "NAL_UNIT_CODED_SLICE_TSA_R",
123
124  "NAL_UNIT_CODED_SLICE_STSA_N",
125  "NAL_UNIT_CODED_SLICE_STSA_R",
126
127  "NAL_UNIT_CODED_SLICE_RADL_N",
128  "NAL_UNIT_CODED_SLICE_RADL_R",
129
130  "NAL_UNIT_CODED_SLICE_RASL_N",
131  "NAL_UNIT_CODED_SLICE_RASL_R",
132
133  "NAL_UNIT_RESERVED_VCL_N10",
134  "NAL_UNIT_RESERVED_VCL_R11",
135  "NAL_UNIT_RESERVED_VCL_N12",
136  "NAL_UNIT_RESERVED_VCL_R13",
137  "NAL_UNIT_RESERVED_VCL_N14",
138  "NAL_UNIT_RESERVED_VCL_R15",
139
140  "NAL_UNIT_CODED_SLICE_BLA_W_LP",
141  "NAL_UNIT_CODED_SLICE_BLA_W_RADL",
142  "NAL_UNIT_CODED_SLICE_BLA_N_LP",
143  "NAL_UNIT_CODED_SLICE_IDR_W_RADL",
144  "NAL_UNIT_CODED_SLICE_IDR_N_LP",
145  "NAL_UNIT_CODED_SLICE_CRA",
146  "NAL_UNIT_RESERVED_IRAP_VCL22",
147  "NAL_UNIT_RESERVED_IRAP_VCL23",
148
149  "NAL_UNIT_RESERVED_VCL24",
150  "NAL_UNIT_RESERVED_VCL25",
151  "NAL_UNIT_RESERVED_VCL26",
152  "NAL_UNIT_RESERVED_VCL27",
153  "NAL_UNIT_RESERVED_VCL28",
154  "NAL_UNIT_RESERVED_VCL29",
155  "NAL_UNIT_RESERVED_VCL30",
156  "NAL_UNIT_RESERVED_VCL31",
157
158  "NAL_UNIT_VPS",
159  "NAL_UNIT_SPS",
160  "NAL_UNIT_PPS",
161  "NAL_UNIT_ACCESS_UNIT_DELIMITER",
162  "NAL_UNIT_EOS",
163  "NAL_UNIT_EOB",
164  "NAL_UNIT_FILLER_DATA",
165  "NAL_UNIT_PREFIX_SEI",
166  "NAL_UNIT_SUFFIX_SEI",
167  "NAL_UNIT_RESERVED_NVCL41",
168  "NAL_UNIT_RESERVED_NVCL42",
169  "NAL_UNIT_RESERVED_NVCL43",
170  "NAL_UNIT_RESERVED_NVCL44",
171  "NAL_UNIT_RESERVED_NVCL45",
172  "NAL_UNIT_RESERVED_NVCL46",
173  "NAL_UNIT_RESERVED_NVCL47",
174  "NAL_UNIT_UNSPECIFIED_48",
175  "NAL_UNIT_UNSPECIFIED_49",
176  "NAL_UNIT_UNSPECIFIED_50",
177  "NAL_UNIT_UNSPECIFIED_51",
178  "NAL_UNIT_UNSPECIFIED_52",
179  "NAL_UNIT_UNSPECIFIED_53",
180  "NAL_UNIT_UNSPECIFIED_54",
181  "NAL_UNIT_UNSPECIFIED_55",
182  "NAL_UNIT_UNSPECIFIED_56",
183  "NAL_UNIT_UNSPECIFIED_57",
184  "NAL_UNIT_UNSPECIFIED_58",
185  "NAL_UNIT_UNSPECIFIED_59",
186  "NAL_UNIT_UNSPECIFIED_60",
187  "NAL_UNIT_UNSPECIFIED_61",
188  "NAL_UNIT_UNSPECIFIED_62",
189  "NAL_UNIT_UNSPECIFIED_63"
190};
191
192typedef struct NalUnitHeader_s
193{
194  int nalUnitType;
195  int nuhLayerId;
196  int nuhTemporalIdPlus1;
197} NalUnitHeader;
198
199
200int findStartCodePrefix(FILE *inFile, int *numStartCodeZeros)
201{
202  int numZeros = 0;
203  int currByte;
204 
205  for (;;)
206  {
207    currByte = fgetc(inFile);
208    if (currByte == EOF)
209    {
210      return 0;
211    }
212
213    if (currByte == 0x01 && numZeros > 1)
214    {
215      *numStartCodeZeros = numZeros;
216      return 1;
217    }
218    else if (currByte == 0)
219    {
220      numZeros++;
221    }
222    else
223    {
224      numZeros = 0;
225    }
226  }
227}
228
229int parseNalUnitHeader(FILE *inFile, NalUnitHeader *nalu)
230{
231  int byte0, byte1;
232
233  byte0 = fgetc(inFile);
234  byte1 = fgetc(inFile);
235
236  if (byte0 == EOF || byte1 == EOF)
237  {
238    return 0;
239  }
240
241  nalu->nalUnitType = (byte0 >> 1) & 0x3f;
242  nalu->nuhLayerId  = (((byte0 << 8) | byte1) >> 3) & 0x3f;
243  nalu->nuhTemporalIdPlus1 = byte1 & 0x07;
244
245  return 1;
246}
247
248void writeStartCodePrefixAndNUH(FILE *outFile, int numStartCodeZeros, NalUnitHeader *nalu)
249{
250  int byte0, byte1;
251  int i;
252
253  /* Start code prefix */
254  if (numStartCodeZeros > 3)
255  {
256    numStartCodeZeros = 3;
257  }
258  for (i = 0; i < numStartCodeZeros; i++)
259  {
260    fputc(0, outFile);
261  }
262  fputc(0x01, outFile);
263
264  /* NAL unit header */
265  byte0 = ((nalu->nalUnitType << 6) | nalu->nuhLayerId) >> 5;
266  byte1 = ((nalu->nuhLayerId << 3) | nalu->nuhTemporalIdPlus1) & 0xff;
267  fputc(byte0, outFile);
268  fputc(byte1, outFile);
269}
270
271int main(int argc, char **argv)
272{
273  FILE *inFile;
274  FILE *outFile;
275  int assignedBaseLayerId;
276  int tIdTarget = 6;
277  NalUnitHeader nalu;
278  int numStartCodeZeros;
279  int nalIsVpsSpsPpsEob;
280  int nalIsVpsSpsPpsEos;
281  int removeNal;
282  int layerIdListTarget[8];
283  int i;
284  int layerIdx;
285  int numLayerIds;
286  char nalName[32];
287
288  if (argc < 5 || argc > 10)
289  {
290    fprintf(stderr, "\n  Usage: ExtractAddLS <infile> <outfile> <max temporal ID> <list of layer IDs> \n\n");
291    fprintf(stderr, "  If only one layer ID 0 is given, base layer extration process is performed\n");
292    fprintf(stderr, "  If only one non-zero layer ID is given, independent non-base layer rewriting\n");
293    fprintf(stderr, "  process is performed\n");
294    fprintf(stderr, "  If more than one layer ID is given, sub-bitstream extraction process for\n");
295    fprintf(stderr, "  additional layer sets is performed (Layer ID list should exactly match\n");
296    fprintf(stderr, "  an additional layer set defined in VPS)\n");
297    exit(1);
298  }
299
300  inFile = fopen(argv[1], "rb");
301  if (inFile == NULL)
302  {
303    fprintf(stderr, "Cannot open input file %s\n", argv[1]);
304    exit(1);
305  }
306
307  outFile = fopen(argv[2], "wb");
308  if (outFile == NULL)
309  {
310    fprintf(stderr, "Cannot open output file %s\n", argv[2]);
311    exit(1);
312  }
313
314  tIdTarget = atoi(argv[3]);
315  if (tIdTarget < 0 || tIdTarget > 6)
316  {
317    fprintf(stderr, "Invalid maximum temporal ID (must be in range 0-6)\n");
318    exit(1);
319  }
320
321  for (i = 4, layerIdx = 0; i < argc; i++, layerIdx++)
322  {
323    layerIdListTarget[layerIdx] = atoi(argv[i]);
324    if (layerIdListTarget[layerIdx] < 0 || layerIdListTarget[layerIdx] > 7)
325    {
326      fprintf(stderr, "Invalid layer ID (must be in range 1-7)\n");
327      exit(1);
328    }
329  }
330
331  numLayerIds = layerIdx;
332  assignedBaseLayerId = layerIdListTarget[0];
333
334  /* Iterate through all NAL units */
335  for (;;)
336  {
337    if (!findStartCodePrefix(inFile, &numStartCodeZeros))
338    {
339      break;
340    }
341    if (!parseNalUnitHeader(inFile, &nalu))
342    {
343      break;
344    }
345
346    if (numLayerIds == 1)
347    {
348      /* base layer or independent non-base layer bitstream extraction */
349
350      /* temporary keep VPS so the extracted/rewriting bitstream can be decoded by HM */
351      nalIsVpsSpsPpsEob = (nalu.nalUnitType == NAL_UNIT_VPS || nalu.nalUnitType == NAL_UNIT_SPS || nalu.nalUnitType == NAL_UNIT_PPS || nalu.nalUnitType == NAL_UNIT_EOB);
352      removeNal = (!nalIsVpsSpsPpsEob && (nalu.nuhLayerId != assignedBaseLayerId))
353                  || (nalIsVpsSpsPpsEob && (nalu.nuhLayerId != 0))
354                  || ((nalu.nuhTemporalIdPlus1 - 1) > tIdTarget);
355      nalu.nuhLayerId = 0;
356    }
357    else /* numLayerIds > 1 */
358    {
359      /* sub-bitstream extraction process for additional layer sets */
360
361      int isTargetLayer = 0;
362
363      for (i = 0; i < numLayerIds; i++)
364      {
365        if (layerIdListTarget[i] == nalu.nuhLayerId)
366        {
367          isTargetLayer = 1;
368        }
369      }
370   
371      nalIsVpsSpsPpsEos = (nalu.nalUnitType == NAL_UNIT_VPS || nalu.nalUnitType == NAL_UNIT_SPS || nalu.nalUnitType == NAL_UNIT_PPS || nalu.nalUnitType == NAL_UNIT_EOS);
372
373      removeNal = (!(nalIsVpsSpsPpsEos || nalu.nalUnitType == NAL_UNIT_EOB) && !isTargetLayer)
374                || (nalIsVpsSpsPpsEos && (nalu.nuhLayerId != 0) && !isTargetLayer)
375                || ((nalu.nuhTemporalIdPlus1 - 1) > tIdTarget);
376    }
377
378    if (!removeNal)
379    {
380      /* Write current NAL unit to output bitstream */
381
382      long naluBytesStartPos;
383      long numNaluBytes;
384      long i;
385
386      printf("Keep  ");
387
388      writeStartCodePrefixAndNUH(outFile, numStartCodeZeros, &nalu);
389
390      naluBytesStartPos = ftell(inFile);
391      /* Find beginning of the next NAL unit to calculate length of the current unit */
392      if (findStartCodePrefix(inFile, &numStartCodeZeros))
393      {
394        numNaluBytes = ftell(inFile) - naluBytesStartPos - numStartCodeZeros - 1;
395      }
396      else
397      {
398        numNaluBytes = ftell(inFile) - naluBytesStartPos;
399      }
400      fseek(inFile, naluBytesStartPos, SEEK_SET);
401
402      i = 0;
403
404      if (numLayerIds == 1 && nalu.nalUnitType == NAL_UNIT_VPS)
405      {
406        char nalByte = fgetc(inFile);
407        nalByte = nalByte | (0x0C);  // set vps_max_layers_minus1 bits(5-4) to 0 for HM decoder
408        nalByte = nalByte & ~(0x03); // set vps_max_layers_minus1 bits(3-0) to 0 for HM decoder
409        fputc(nalByte, outFile); 
410        i++;
411        nalByte = fgetc(inFile);
412        nalByte = nalByte & ~(0xF0);
413        fputc(nalByte, outFile); 
414        i++;
415      }
416      else if (numLayerIds > 1 && nalu.nalUnitType == NAL_UNIT_VPS)
417      {
418        /* sub-bitstream extraction process for additional layer sets */
419        int nalByte = fgetc(inFile);
420        nalByte = nalByte & ~(0x04);  /* vps_base_layer_available_flag in each VPS is set equal to 0 */
421        fputc(nalByte, outFile);
422        i++;
423      }
424
425      for (; i < numNaluBytes; i++)
426      {
427        fputc(fgetc(inFile), outFile);
428      }
429    }
430    else
431    {
432      printf("-     ");
433    }
434
435    strcpy(nalName, nalUnitNames[nalu.nalUnitType]);
436    for (i = strlen(nalName); i < 31; i++)
437    {
438      nalName[i] = ' ';
439    }
440    nalName[31] = '\0';
441
442    printf("%s  layer ID: %i  temporal ID: %i\n", nalName, nalu.nuhLayerId, nalu.nuhTemporalIdPlus1 - 1);
443  }
444
445  fclose(inFile);
446  fclose(outFile);
447
448
449  return 0;
450}
Note: See TracBrowser for help on using the repository browser.