JM8.6中NALU(此处指VCL式的NALU)是如何写进码流的?

       在lencod.c的main函数中调用了encode_one_slice函数,在encode_one_slice函数中调用了frame_picture函数,调用了frame_picture函数后(frame_picture还会继续调用其他重要函数) 就实现了对第一帧的编码,这样全局变量frame_pic就发生了变化,得到了它想得到的码流,现在要写码流,怎么写呢?

      在encode_one_frame中接着就调用到了writeout_picture函数,调用形式是:

writeout_picture (frame_pic);

      可见,把代码码流信息的frame_pic穿进去了,进入writeout_picture函数看看:

static int writeout_picture(Picture *pic)
{
  Bitstream *currStream;
  int partition, slice;
  Slice *currSlice;

  img->currentPicture=pic;

  // 遍历slice,通常,一个frame对应一个slice
  for (slice=0; slice<pic->no_slices; slice++)
  {
    currSlice = pic->slices[slice];
    
	// 目前都发现currSlice->max_part_nr为1
	for (partition=0; partition<currSlice->max_part_nr; partition++)
    {
      currStream = (currSlice->partArr[partition]).bitstream;
      
	  // currStream->bits_to_go相当于标记,必须为8
	  assert (currStream->bits_to_go == 8);    //! should always be the case, the 
                                               //! byte alignment is done in terminate_slice
	  

	  // writeUnit函数的第一参数类型是Bitstream*
	  writeUnit (currSlice->partArr[partition].bitstream,partition);

    }           // partition loop

  }           // slice loop
  
  return 0;   
}

      可以看到,把一个picture对应的码流分成slice和数据分块来传给writeUnit的形参(一般认为:一个slice对应一个数据分块),进入到writeUnit函数看看:

static void writeUnit(Bitstream* currStream,int partition)
{
  NALU_t *nalu;

  // 实际上currStream->bits_to_go就是一个标记
  // 如果不为8, 则表明往下继续执行会有错误
  assert (currStream->bits_to_go == 8);

  // 分配堆空间, *4是为了安全起见
  nalu = AllocNALU(img->width*img->height*4);

  nalu->startcodeprefix_len = 2+(img->current_mb_nr == 0?ZEROBYTES_SHORTSTARTCODE+1:ZEROBYTES_SHORTSTARTCODE);
//printf ("nalu->startcodeprefix_len %d\n", nalu->startcodeprefix_len);
  
  nalu->len = currStream->byte_pos +1;            // add one for the first byte of the NALU
//printf ("nalu->len %d\n", nalu->len);


  // 内存数据复制,这个是最重要的.
  memcpy (&nalu->buf[1], currStream->streamBuffer, nalu->len-1);
  
  // 下面对nalu的一些参数进行赋值
  // 其实就是对nalu header的8个比特赋值
  if (img->currentPicture->idr_flag)
  {
    nalu->nal_unit_type = NALU_TYPE_IDR;
    nalu->nal_reference_idc = NALU_PRIORITY_HIGHEST;
  }
  else if (img->type == B_SLICE)
  {
	
	//different nal header for different partitions
    if(input->partition_mode == 0)
	{
      nalu->nal_unit_type = NALU_TYPE_SLICE;
	}
	else
	{
      nalu->nal_unit_type = NALU_TYPE_DPA +  partition;
	}
    
    if (img->nal_reference_idc !=0)
	{
		nalu->nal_reference_idc = NALU_PRIORITY_HIGH;
	}
    else
    {
      nalu->nal_reference_idc = NALU_PRIORITY_DISPOSABLE;
    }

  }
  else   // non-b frame, non IDR slice
  {
	
	//different nal header for different partitions
    if(input->partition_mode == 0)
    {
       nalu->nal_unit_type = NALU_TYPE_SLICE;
	}
	else
	{
       nalu->nal_unit_type = NALU_TYPE_DPA +  partition;
	}
    if (img->nal_reference_idc !=0)
    {
       nalu->nal_reference_idc = NALU_PRIORITY_HIGH;
    }
    else
    {
       nalu->nal_reference_idc = NALU_PRIORITY_DISPOSABLE;
    }

  }

  nalu->forbidden_bit = 0; // 必须为0


  // WriteNALU是指向函数的全局指针(提前赋值了),
  // 所以要想用鼠标进入WriteNALU“函数”是不可能的

  // 真正调用到的函数是:WriteAnnexbNALU
  // 而WriteAnnexbNALU函数就是写码流函数
  stat->bit_ctr += WriteNALU (nalu); // 写码流
  
  FreeNALU(nalu);
}


       不用再进入WriteAnnexbNALU函数了,因为,对这个函数太熟悉了.

你可能感兴趣的:(JM8.6中NALU(此处指VCL式的NALU)是如何写进码流的?)