/*----------------------------------------------------------------------
|   AP4_CbcStreamCipher::SetIV
+---------------------------------------------------------------------*/
AP4_Result
AP4_CbcStreamCipher::SetIV(const AP4_UI08* iv)
{
    AP4_CopyMemory(m_Iv, iv, AP4_CIPHER_BLOCK_SIZE);
    m_StreamOffset = 0;
    m_Eos = false;
    AP4_CopyMemory(m_ChainBlock, m_Iv, AP4_CIPHER_BLOCK_SIZE);
    m_ChainBlockFullness = AP4_CIPHER_BLOCK_SIZE;
    m_InBlockFullness = 0;
    m_OutputSkip = 0;
    return AP4_SUCCESS;
}
Ejemplo n.º 2
0
/*----------------------------------------------------------------------
|   AP4_OmaDcfCtrSampleEncrypter::EncryptSampleData
+---------------------------------------------------------------------*/
AP4_Result
AP4_OmaDcfCtrSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
        AP4_DataBuffer& data_out,
        AP4_UI64        counter,
        bool            /*skip_encryption*/)
{
    // setup the buffers
    const unsigned char* in = data_in.GetData();
    AP4_CHECK(data_out.SetDataSize(data_in.GetDataSize()+AP4_CIPHER_BLOCK_SIZE+1));
    unsigned char* out = data_out.UseData();

    // selective encryption flag
    *out++ = 0x80;

    // IV on 16 bytes: [SSSSSSSSXXXXXXXX]
    // where SSSSSSSS is the 64-bit salt and
    // XXXXXXXX is the 64-bit base counter
    AP4_CopyMemory(out, m_Salt, 8);
    AP4_BytesFromUInt64BE(&out[8], counter);

    // encrypt the payload
    AP4_Size data_size = data_in.GetDataSize();
    m_Cipher->SetIV(out);
    m_Cipher->ProcessBuffer(in, data_size, out+AP4_CIPHER_BLOCK_SIZE);

    return AP4_SUCCESS;
}
Ejemplo n.º 3
0
/*----------------------------------------------------------------------
|   AP4_OmaDcfCbcSampleEncrypter::EncryptSampleData
+---------------------------------------------------------------------*/
AP4_Result
AP4_OmaDcfCbcSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
        AP4_DataBuffer& data_out,
        AP4_UI64        counter,
        bool            /*skip_encryption*/)
{
    // make sure there is enough space in the output buffer
    data_out.Reserve(data_in.GetDataSize()+2*AP4_CIPHER_BLOCK_SIZE+1);

    // setup the buffers
    AP4_Size out_size = data_in.GetDataSize()+AP4_CIPHER_BLOCK_SIZE;
    unsigned char* out = data_out.UseData();

    // selective encryption flag
    *out++ = 0x80;

    // IV on 16 bytes: [SSSSSSSSXXXXXXXX]
    // where SSSSSSSS is the 64-bit salt and
    // XXXXXXXX is the 64-bit base counter
    AP4_CopyMemory(out, m_Salt, 8);
    AP4_BytesFromUInt64BE(&out[8], counter);

    // encrypt the payload
    m_Cipher->SetIV(out);
    m_Cipher->ProcessBuffer(data_in.GetData(),
                            data_in.GetDataSize(),
                            out+AP4_CIPHER_BLOCK_SIZE,
                            &out_size,
                            true);
    AP4_CHECK(data_out.SetDataSize(out_size+AP4_CIPHER_BLOCK_SIZE+1));

    return AP4_SUCCESS;
}
Ejemplo n.º 4
0
/*----------------------------------------------------------------------
|   AP4_MemoryByteStream::ReadPartial
+---------------------------------------------------------------------*/
AP4_Result 
AP4_MemoryByteStream::ReadPartial(void*     buffer, 
                                  AP4_Size  bytes_to_read, 
                                  AP4_Size& bytes_read)
{
    // default values
    bytes_read = 0;

    // shortcut
    if (bytes_to_read == 0) {
        return AP4_SUCCESS;
    }

    // clamp to range
    if (m_Position+bytes_to_read > m_Buffer->GetDataSize()) {
        bytes_to_read = (AP4_Size)(m_Buffer->GetDataSize() - m_Position);
    }

    // check for end of stream
    if (bytes_to_read == 0) {
        return AP4_ERROR_EOS;
    }

    // read from the memory
    AP4_CopyMemory(buffer, m_Buffer->GetData()+m_Position, bytes_to_read);
    m_Position += bytes_to_read;

    bytes_read = bytes_to_read;

    return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
|   AP4_CbcStreamCipher::SetStreamOffset
+---------------------------------------------------------------------*/
AP4_Result
AP4_CbcStreamCipher::SetStreamOffset(AP4_UI64       offset,
                                     AP4_Cardinal*  preroll)
{
    // does not make sense for encryption
    if (m_BlockCipher->GetDirection() == AP4_BlockCipher::ENCRYPT) {
        return AP4_ERROR_NOT_SUPPORTED;
    }
    
    // check params
    if (preroll == NULL) return AP4_ERROR_INVALID_PARAMETERS;

    // reset the end of stream flag
    m_Eos = false;
    
    // invalidate the chain block
    m_ChainBlockFullness = 0;
    
    // flush cached data
    m_InBlockFullness = 0;
    
    // compute the preroll
    if (offset < AP4_CIPHER_BLOCK_SIZE) {
        AP4_CopyMemory(m_ChainBlock, m_Iv, AP4_CIPHER_BLOCK_SIZE);
        m_ChainBlockFullness = AP4_CIPHER_BLOCK_SIZE;
        *preroll = (AP4_Cardinal)offset;
    } else {
        *preroll = (AP4_Cardinal) ((offset%AP4_CIPHER_BLOCK_SIZE) + AP4_CIPHER_BLOCK_SIZE);
    }
    
    m_StreamOffset = offset-*preroll;
    m_OutputSkip   = (AP4_Size)(offset%AP4_CIPHER_BLOCK_SIZE);
    return AP4_SUCCESS;
}
Ejemplo n.º 6
0
/*----------------------------------------------------------------------
|   AP4_MarlinIpmpTrackEncrypter:ProcessSample
+---------------------------------------------------------------------*/
AP4_Result 
AP4_MarlinIpmpTrackEncrypter::ProcessSample(AP4_DataBuffer& data_in,
                                            AP4_DataBuffer& data_out)
{
    AP4_Result result;
    
    const AP4_UI08* in = data_in.GetData();
    AP4_Size        in_size = data_in.GetDataSize();

    // default to 0 output 
    data_out.SetDataSize(0);

    // process the sample data
    AP4_Size out_size = AP4_CIPHER_BLOCK_SIZE*(2+(in_size/AP4_CIPHER_BLOCK_SIZE));
    data_out.SetDataSize(out_size);
    AP4_UI08* out = data_out.UseData();

    // write the IV
    AP4_CopyMemory(out, m_IV, AP4_CIPHER_BLOCK_SIZE);
    out_size -= AP4_CIPHER_BLOCK_SIZE;
    
    // encrypt the data
    m_Cipher->SetIV(m_IV);
    result = m_Cipher->ProcessBuffer(in, 
                                     in_size, 
                                     out+AP4_AES_BLOCK_SIZE,
                                     &out_size,
                                     true);
    if (AP4_FAILED(result)) return result;
    
    // update the payload size
    data_out.SetDataSize(out_size+AP4_AES_BLOCK_SIZE);
    
    return AP4_SUCCESS;
}
Ejemplo n.º 7
0
/*----------------------------------------------------------------------
|   AP4_MarlinIpmpTrackEncrypter::AP4_MarlinIpmpTrackEncrypter
+---------------------------------------------------------------------*/
AP4_MarlinIpmpTrackEncrypter::AP4_MarlinIpmpTrackEncrypter(AP4_StreamCipher* cipher, 
                                                           const AP4_UI08*   iv) :
    m_Cipher(cipher)
{
    // copy the IV
    AP4_CopyMemory(m_IV, iv, AP4_AES_BLOCK_SIZE);    
}
Ejemplo n.º 8
0
/*----------------------------------------------------------------------
|   AP4_OmaDcfCtrSampleDecrypter::DecryptSampleData
+---------------------------------------------------------------------*/
AP4_Result
AP4_OmaDcfCtrSampleDecrypter::DecryptSampleData(AP4_DataBuffer& data_in,
        AP4_DataBuffer& data_out,
        const AP4_UI08* /*iv*/)
{
    bool                 is_encrypted = true;
    const unsigned char* in = data_in.GetData();
    AP4_Size             in_size = data_in.GetDataSize();

    // default to 0 output
    AP4_CHECK(data_out.SetDataSize(0));

    // check the selective encryption flag
    if (m_SelectiveEncryption) {
        if (in_size < 1) return AP4_ERROR_INVALID_FORMAT;
        is_encrypted = ((in[0]&0x80)!=0);
        in++;
    }

    // check the size
    unsigned int header_size = (m_SelectiveEncryption?1:0)+(is_encrypted?m_IvLength:0);
    if (header_size > in_size) return AP4_ERROR_INVALID_FORMAT;

    // process the sample data
    AP4_Size payload_size = in_size-header_size;
    AP4_CHECK(data_out.Reserve(payload_size));
    unsigned char* out = data_out.UseData();
    if (is_encrypted) {
        // set the IV
        if (m_IvLength == 16) {
            m_Cipher->SetIV(in);
        } else {
            AP4_UI08 iv[16];
            AP4_SetMemory(iv, 0, 16);
            AP4_CopyMemory(iv+16-m_IvLength, in, m_IvLength);
            m_Cipher->SetIV(iv);
        }
        AP4_CHECK(m_Cipher->ProcessBuffer(in+m_IvLength,
                                          payload_size,
                                          out));
    } else {
        AP4_CopyMemory(out, in, payload_size);
    }
    AP4_CHECK(data_out.SetDataSize(payload_size));

    return AP4_SUCCESS;
}
Ejemplo n.º 9
0
/*----------------------------------------------------------------------
|   AP4_BlocAtom::SetPurchaseLocation
+---------------------------------------------------------------------*/
void
AP4_BlocAtom::SetPurchaseLocation(const char* purchase_location)
{
    unsigned int len = (unsigned int)AP4_StringLength(purchase_location);
    if (len > 256) len = 256;
    AP4_CopyMemory(m_PurchaseLocation, purchase_location, len);
    AP4_SetMemory(&m_PurchaseLocation[len], 0, 256-len+1);
}
Ejemplo n.º 10
0
/*----------------------------------------------------------------------
|   AP4_StcoAtom::AP4_StcoAtom
+---------------------------------------------------------------------*/
AP4_StcoAtom::AP4_StcoAtom(AP4_UI32* entries, AP4_UI32 entry_count) :
AP4_Atom(AP4_ATOM_TYPE_STCO,  
         AP4_FULL_ATOM_HEADER_SIZE+4+entry_count*4,
         0, 0),
         m_Entries(new AP4_UI32[entry_count]),
         m_EntryCount(entry_count)
{
    AP4_CopyMemory(m_Entries, entries, m_EntryCount*4);
}
SampleFileStorage::SampleFileStorage(const char *basename) {
        m_Stream = NULL;
        AP4_Size name_length = (AP4_Size)AP4_StringLength(basename);
        char* filename = new char[name_length+2];
        AP4_CopyMemory(filename, basename, name_length);
        filename[name_length]   = '_';
        filename[name_length+1] = '\0';
        m_Filename = filename;
        delete[] filename;
}
Ejemplo n.º 12
0
/*----------------------------------------------------------------------
|   MakeFramePrefix
+---------------------------------------------------------------------*/
static AP4_Result
MakeFramePrefix(AP4_SampleDescription* sdesc, AP4_DataBuffer& prefix, unsigned int& nalu_length_size)
{
    AP4_AvcSampleDescription* avc_desc = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, sdesc);
    if (avc_desc == NULL) {
        fprintf(stderr, "ERROR: track does not contain an AVC stream\n");
        return AP4_FAILURE;
    }
    
    if (sdesc->GetFormat() == AP4_SAMPLE_FORMAT_AVC3 || sdesc->GetFormat() == AP4_SAMPLE_FORMAT_AVC4) {
        // no need for a prefix, SPS/PPS NALs should be in the elementary stream already
        return AP4_SUCCESS;
    }
    
    // make the SPS/PPS prefix
    nalu_length_size = avc_desc->GetNaluLengthSize();
    for (unsigned int i=0; i<avc_desc->GetSequenceParameters().ItemCount(); i++) {
        AP4_DataBuffer& buffer = avc_desc->GetSequenceParameters()[i];
        unsigned int prefix_size = prefix.GetDataSize();
        prefix.SetDataSize(prefix_size+4+buffer.GetDataSize());
        unsigned char* p = prefix.UseData()+prefix_size;
        *p++ = 0;
        *p++ = 0;
        *p++ = 0;
        *p++ = 1;
        AP4_CopyMemory(p, buffer.GetData(), buffer.GetDataSize());
    }
    for (unsigned int i=0; i<avc_desc->GetPictureParameters().ItemCount(); i++) {
        AP4_DataBuffer& buffer = avc_desc->GetPictureParameters()[i];
        unsigned int prefix_size = prefix.GetDataSize();
        prefix.SetDataSize(prefix_size+4+buffer.GetDataSize());
        unsigned char* p = prefix.UseData()+prefix_size;
        *p++ = 0;
        *p++ = 0;
        *p++ = 0;
        *p++ = 1;
        AP4_CopyMemory(p, buffer.GetData(), buffer.GetDataSize());
    }
    
    return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
|   AP4_CtrStreamCipher::SetIV
+---------------------------------------------------------------------*/
AP4_Result
AP4_CtrStreamCipher::SetIV(const AP4_UI08* iv)
{
    if (iv) {
        AP4_CopyMemory(m_IV, iv, AP4_CIPHER_BLOCK_SIZE);
    } else {
        AP4_SetMemory(m_IV, 0, AP4_CIPHER_BLOCK_SIZE);
    }

    // for the stream offset back to 0
    m_CacheValid = false;
    return SetStreamOffset(0);
}
Ejemplo n.º 14
0
/*----------------------------------------------------------------------
|   AP4_AvccAtom::UpdateRawBytes
+---------------------------------------------------------------------*/
void
AP4_AvccAtom::UpdateRawBytes()
{
    // compute the payload size
    unsigned int payload_size = 6;    
    for (unsigned int i=0; i<m_SequenceParameters.ItemCount(); i++) {
        payload_size += 2+m_SequenceParameters[i].GetDataSize();
    }
    ++payload_size;
    for (unsigned int i=0; i<m_PictureParameters.ItemCount(); i++) {
        payload_size += 2+m_PictureParameters[i].GetDataSize();
    }
    m_RawBytes.SetDataSize(payload_size);
    AP4_UI08* payload = m_RawBytes.UseData();

    payload[0] = m_ConfigurationVersion;
    payload[1] = m_Profile;
    payload[2] = m_ProfileCompatibility;
    payload[3] = m_Level;
    payload[4] = 0xFC | (m_NaluLengthSize-1);
    payload[5] = 0xE0 | m_SequenceParameters.ItemCount();
    unsigned int cursor = 6;
    for (unsigned int i=0; i<m_SequenceParameters.ItemCount(); i++) {
        AP4_UI16 param_length = (AP4_UI16)m_SequenceParameters[i].GetDataSize();
        AP4_BytesFromUInt16BE(&payload[cursor], param_length);
        cursor += 2;
        AP4_CopyMemory(&payload[cursor], m_SequenceParameters[i].GetData(), param_length);
        cursor += param_length;
    }
    payload[cursor++] = m_PictureParameters.ItemCount();
    for (unsigned int i=0; i<m_PictureParameters.ItemCount(); i++) {
        AP4_UI16 param_length = (AP4_UI16)m_PictureParameters[i].GetDataSize();
        AP4_BytesFromUInt16BE(&payload[cursor], param_length);
        cursor += 2;
        AP4_CopyMemory(&payload[cursor], m_PictureParameters[i].GetData(), param_length);
        cursor += param_length;
    }
}
Ejemplo n.º 15
0
/*----------------------------------------------------------------------
|   AP4_MkidAtom::AddEntry
+---------------------------------------------------------------------*/
AP4_Result              
AP4_MkidAtom::AddEntry(const AP4_UI08* kid, const char* content_id)
{
    unsigned int content_id_size = (unsigned int)AP4_StringLength(content_id);
    unsigned int entry_count = m_Entries.ItemCount();

    // add the entry
    m_Entries.SetItemCount(entry_count+1);
    AP4_CopyMemory(m_Entries[entry_count].m_KID, kid, 16);
    m_Entries[entry_count].m_ContentId.Assign(content_id, content_id_size);

    // update the size
    m_Size32 += 4+16+content_id_size;

    return AP4_SUCCESS;
}
Ejemplo n.º 16
0
/*----------------------------------------------------------------------
|   AP4_OmaDbcCbcSampleDecrypter::DecryptSampleData
+---------------------------------------------------------------------*/
AP4_Result
AP4_OmaDcfCbcSampleDecrypter::DecryptSampleData(AP4_DataBuffer& data_in,
        AP4_DataBuffer& data_out,
        const AP4_UI08* /*iv*/)
{
    bool                 is_encrypted = true;
    const unsigned char* in = data_in.GetData();
    AP4_Size             in_size = data_in.GetDataSize();
    AP4_Size             out_size;

    // default to 0 output
    AP4_CHECK(data_out.SetDataSize(0));

    // check the selective encryption flag
    if (m_SelectiveEncryption) {
        if (in_size < 1) return AP4_ERROR_INVALID_FORMAT;
        is_encrypted = ((in[0]&0x80)!=0);
        in++;
    }

    // check the size
    unsigned int header_size = (m_SelectiveEncryption?1:0)+(is_encrypted?m_IvLength:0);
    if (header_size > in_size) return AP4_ERROR_INVALID_FORMAT;

    // process the sample data
    unsigned int payload_size = in_size-header_size;
    data_out.Reserve(payload_size);
    unsigned char* out = data_out.UseData();
    if (is_encrypted) {
        // get the IV
        const AP4_UI08* iv = (const AP4_UI08*)in;
        in += AP4_CIPHER_BLOCK_SIZE;

        m_Cipher->SetIV(iv);
        out_size = payload_size;
        AP4_CHECK(m_Cipher->ProcessBuffer(in, payload_size, out, &out_size, true));
    } else {
        AP4_CopyMemory(out, in, payload_size);
        out_size = payload_size;
    }

    AP4_CHECK(data_out.SetDataSize(out_size));

    return AP4_SUCCESS;
}
Ejemplo n.º 17
0
/*----------------------------------------------------------------------
|   AP4_MemoryByteStream::WritePartial
+---------------------------------------------------------------------*/
AP4_Result 
AP4_MemoryByteStream::WritePartial(const void* buffer, 
                                   AP4_Size    bytes_to_write, 
                                   AP4_Size&   bytes_written)
{
    // default values
    bytes_written = 0;

    // shortcut
    if (bytes_to_write == 0) {
        return AP4_SUCCESS;
    }

    // check that we don't exceed the max
    if (m_Position+bytes_to_write > (AP4_Position)AP4_MEMORY_BYTE_STREAM_MAX_SIZE) {
        return AP4_ERROR_OUT_OF_RANGE;
    }

    // reserve space in the buffer
    AP4_Result result = m_Buffer->Reserve((AP4_Size)(m_Position+bytes_to_write));
    if (AP4_SUCCEEDED(result)) {
        m_Buffer->SetDataSize((AP4_Size)(m_Position+bytes_to_write));
    } else {
        // failed to reserve, most likely caused by a buffer that has
        // external storage
        if (m_Position+bytes_to_write > m_Buffer->GetDataSize()) {
            bytes_to_write = (AP4_Size)(m_Buffer->GetDataSize() - m_Position);
        }
    } 

    // check for en of stream
    if (bytes_to_write == 0) {
        return AP4_ERROR_EOS;
    }

    // write to memory
    AP4_CopyMemory((void*)(m_Buffer->UseData()+m_Position), buffer, bytes_to_write);
    m_Position += bytes_to_write;

    bytes_written = bytes_to_write;

    return AP4_SUCCESS;
}
Ejemplo n.º 18
0
/*----------------------------------------------------------------------
|   AP4_BufferedInputStream::ReadPartial
+---------------------------------------------------------------------*/
AP4_Result 
AP4_BufferedInputStream::ReadPartial(void*     buffer, 
                                     AP4_Size  bytes_to_read, 
                                     AP4_Size& bytes_read)
{
    // check for shortcut
    if (bytes_to_read == 0) {
        bytes_read = 0;
        return AP4_SUCCESS;
    }
    
    // compute how much data is available in the buffer
    assert(m_BufferPosition <= m_Buffer.GetDataSize());
    AP4_Size available = m_Buffer.GetDataSize()-m_BufferPosition;
    
    // refill the buffer if it is empty
    if (available == 0) {
        AP4_Result result = Refill();
        if (AP4_FAILED(result)) {
            bytes_read = 0;
            return result;
        }
        assert(m_BufferPosition == 0);
        assert(m_Buffer.GetDataSize() != 0);
        available = m_Buffer.GetDataSize()-m_BufferPosition;
    }
    
    // clamp the number of bytes to read to what's available
    if (bytes_to_read > available) bytes_to_read = available;
    bytes_read = bytes_to_read;
    
    // copy the buffered data
    AP4_CopyMemory(buffer, m_Buffer.GetData()+m_BufferPosition, bytes_to_read);
    m_BufferPosition += bytes_to_read;
    assert(m_BufferPosition <= m_Buffer.GetDataSize());
    
    return AP4_SUCCESS;
}
Ejemplo n.º 19
0
/*----------------------------------------------------------------------
|   AP4_UuidAtom::AP4_UuidAtom
+---------------------------------------------------------------------*/
AP4_UuidAtom::AP4_UuidAtom(AP4_UI64 size, const AP4_UI08* uuid) : 
    AP4_Atom(AP4_ATOM_TYPE_UUID, size)
{
    AP4_CopyMemory(m_Uuid, uuid, 16);
}
/*----------------------------------------------------------------------
|   AP4_CbcStreamCipher::DecryptBuffer
+---------------------------------------------------------------------*/
AP4_Result
AP4_CbcStreamCipher::DecryptBuffer(const AP4_UI08* in, 
                                   AP4_Size        in_size,
                                   AP4_UI08*       out, 
                                   AP4_Size*       out_size,
                                   bool            is_last_buffer)
{
    // we don't do much checking here because this method is only called
    // from ProcessBuffer(), which does all the parameter checking
    
    // deal chain-block buffering
    if (m_ChainBlockFullness != AP4_CIPHER_BLOCK_SIZE) {
        unsigned int needed = AP4_CIPHER_BLOCK_SIZE-m_ChainBlockFullness;
        unsigned int chunk = (in_size > needed) ? needed : in_size;
        AP4_CopyMemory(&m_ChainBlock[m_ChainBlockFullness], in, chunk);
        in_size              -= chunk;
        in                   += chunk;
        m_ChainBlockFullness += chunk;
        m_StreamOffset       += chunk;
        if (m_ChainBlockFullness != AP4_CIPHER_BLOCK_SIZE) {
            // not enough to continue
            *out_size = 0;
            return AP4_SUCCESS;
        }
    }
    AP4_ASSERT(m_ChainBlockFullness == AP4_CIPHER_BLOCK_SIZE);
        
    // compute how many blocks we span
    AP4_UI64 start_block   = (m_StreamOffset-m_InBlockFullness)/AP4_CIPHER_BLOCK_SIZE;
    AP4_UI64 end_block     = (m_StreamOffset+in_size)/AP4_CIPHER_BLOCK_SIZE;
    AP4_UI32 blocks_needed = (AP4_UI32)(end_block-start_block);

    // compute how many blocks we will need to produce
    if (*out_size < blocks_needed*AP4_CIPHER_BLOCK_SIZE) {
        *out_size = blocks_needed*AP4_CIPHER_BLOCK_SIZE;
        return AP4_ERROR_BUFFER_TOO_SMALL;
    }
    *out_size = blocks_needed*AP4_CIPHER_BLOCK_SIZE;
    if (blocks_needed && m_OutputSkip) *out_size -= m_OutputSkip;

    // shortcut
    if (in_size == 0) return AP4_SUCCESS;
    
    // deal with in-block buffering
    // NOTE: if we have bytes to skip on output, always use the in-block buffer for
    // the first block, even if we're aligned, this makes the code simpler
    AP4_ASSERT(m_InBlockFullness < AP4_CIPHER_BLOCK_SIZE);
    if (m_OutputSkip || m_InBlockFullness) {
        unsigned int needed = AP4_CIPHER_BLOCK_SIZE-m_InBlockFullness;
        unsigned int chunk = (in_size > needed) ? needed : in_size;
        AP4_CopyMemory(&m_InBlock[m_InBlockFullness], in, chunk);
        in_size           -= chunk;
        in                += chunk;
        m_InBlockFullness += chunk;
        m_StreamOffset    += chunk;
        if (m_InBlockFullness != AP4_CIPHER_BLOCK_SIZE) {
            // not enough to continue
            *out_size = 0;
            return AP4_SUCCESS;
        }
        AP4_UI08 out_block[AP4_CIPHER_BLOCK_SIZE];
        AP4_Result result = m_BlockCipher->Process(m_InBlock, AP4_CIPHER_BLOCK_SIZE, out_block, m_ChainBlock);
        m_InBlockFullness = 0;
        if (AP4_FAILED(result)) {
            *out_size = 0;
            return result;
        }
        AP4_CopyMemory(m_ChainBlock, m_InBlock, AP4_CIPHER_BLOCK_SIZE);
        if (m_OutputSkip) {
            AP4_ASSERT(m_OutputSkip < AP4_CIPHER_BLOCK_SIZE);
            AP4_CopyMemory(out, &out_block[m_OutputSkip], AP4_CIPHER_BLOCK_SIZE-m_OutputSkip);
            out += AP4_CIPHER_BLOCK_SIZE-m_OutputSkip;
            m_OutputSkip = 0;
        } else {
            AP4_CopyMemory(out, out_block, AP4_CIPHER_BLOCK_SIZE);
            out += AP4_CIPHER_BLOCK_SIZE;
        }
    }
    AP4_ASSERT(m_InBlockFullness == 0);
    AP4_ASSERT(m_OutputSkip == 0);
    
    // process full blocks
    unsigned int block_count = in_size/AP4_CIPHER_BLOCK_SIZE;
    if (block_count) {
        AP4_UI32 blocks_size = block_count*AP4_CIPHER_BLOCK_SIZE;
        AP4_Result result = m_BlockCipher->Process(in, blocks_size, out, m_ChainBlock);
        AP4_CopyMemory(m_ChainBlock, in+blocks_size-AP4_CIPHER_BLOCK_SIZE, AP4_CIPHER_BLOCK_SIZE);
        if (AP4_FAILED(result)) {
            *out_size = 0;
            return result;
        }
        in             += blocks_size;
        out            += blocks_size;
        in_size        -= blocks_size;
        m_StreamOffset += blocks_size;
    }

    // buffer partial block leftovers
    if (in_size) {
        AP4_ASSERT(in_size < AP4_CIPHER_BLOCK_SIZE);
        AP4_CopyMemory(m_InBlock, in, in_size);
        m_InBlockFullness = in_size;
        m_StreamOffset   += in_size;
    }
    
    // deal with padding
    if (is_last_buffer) {
        AP4_UI08 pad_byte = *(out-1);
        if (pad_byte > AP4_CIPHER_BLOCK_SIZE ||
            *out_size < pad_byte) {
            *out_size = 0;
            return AP4_ERROR_INVALID_FORMAT;
        }
        *out_size -= pad_byte;
    }
    
    return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
|   AP4_CbcStreamCipher::EncryptBuffer
+---------------------------------------------------------------------*/
AP4_Result
AP4_CbcStreamCipher::EncryptBuffer(const AP4_UI08* in, 
                                   AP4_Size        in_size,
                                   AP4_UI08*       out, 
                                   AP4_Size*       out_size,
                                   bool            is_last_buffer)
{
    // we don't do much checking here because this method is only called
    // from ProcessBuffer(), which does all the parameter checking
    
    // compute how many blocks we span
    AP4_UI64 start_block   = (m_StreamOffset-m_InBlockFullness)/AP4_CIPHER_BLOCK_SIZE;
    AP4_UI64 end_block     = (m_StreamOffset+in_size)/AP4_CIPHER_BLOCK_SIZE;
    AP4_UI32 blocks_needed = (AP4_UI32)(end_block-start_block);
 
    // compute how many blocks we will need to produce
    if (is_last_buffer) {
        ++blocks_needed;
    }
    if (*out_size < blocks_needed*AP4_CIPHER_BLOCK_SIZE) {
        *out_size = blocks_needed*AP4_CIPHER_BLOCK_SIZE;
        return AP4_ERROR_BUFFER_TOO_SMALL;
    }
    *out_size = blocks_needed*AP4_CIPHER_BLOCK_SIZE;

    // finish any incomplete block from a previous call
    unsigned int offset = (unsigned int)(m_StreamOffset%AP4_CIPHER_BLOCK_SIZE);
    AP4_ASSERT(m_InBlockFullness == offset);
    if (offset) {
        unsigned int chunk = AP4_CIPHER_BLOCK_SIZE-offset;
        if (chunk > in_size) chunk = in_size;
        for (unsigned int x=0; x<chunk; x++) {
            m_InBlock[x+offset] = in[x];
        }
        in                += chunk;
        in_size           -= chunk;
        m_StreamOffset    += chunk;        
        m_InBlockFullness += chunk;
        if (offset+chunk == AP4_CIPHER_BLOCK_SIZE) {
            // we have filled the input block, encrypt it
            AP4_Result result = m_BlockCipher->Process(m_InBlock, AP4_CIPHER_BLOCK_SIZE, out, m_ChainBlock);
            AP4_CopyMemory(m_ChainBlock, out, AP4_CIPHER_BLOCK_SIZE);
            m_InBlockFullness = 0;
            if (AP4_FAILED(result)) {
                *out_size = 0;
                return result;
            }
            out += AP4_CIPHER_BLOCK_SIZE;
        }
    }
    
    // encrypt the whole blocks
    unsigned int block_count = in_size/AP4_CIPHER_BLOCK_SIZE;
    if (block_count) {
        AP4_ASSERT(m_InBlockFullness == 0);
        AP4_UI32 blocks_size = block_count*AP4_CIPHER_BLOCK_SIZE;
        AP4_Result result = m_BlockCipher->Process(in, blocks_size, out, m_ChainBlock);
        AP4_CopyMemory(m_ChainBlock, out+blocks_size-AP4_CIPHER_BLOCK_SIZE, AP4_CIPHER_BLOCK_SIZE);
        if (AP4_FAILED(result)) {
            *out_size = 0;
            return result;
        }
        in             += blocks_size;
        out            += blocks_size;
        in_size        -= blocks_size;
        m_StreamOffset += blocks_size;
    }
    
    // deal with what's left
    if (in_size) {
        AP4_ASSERT(in_size < AP4_CIPHER_BLOCK_SIZE);
        for (unsigned int x=0; x<in_size; x++) {
            m_InBlock[x+m_InBlockFullness] = in[x];
        }
        m_InBlockFullness += in_size;
        m_StreamOffset    += in_size;
    }
    
    // pad if needed 
    if (is_last_buffer) {
        AP4_ASSERT(m_InBlockFullness == m_StreamOffset%AP4_CIPHER_BLOCK_SIZE);
        AP4_UI08 pad_byte = AP4_CIPHER_BLOCK_SIZE-(AP4_UI08)(m_StreamOffset%AP4_CIPHER_BLOCK_SIZE);
        for (unsigned int x=AP4_CIPHER_BLOCK_SIZE-pad_byte; x<AP4_CIPHER_BLOCK_SIZE; x++) {
            m_InBlock[x] = pad_byte;
        }
        AP4_Result result = m_BlockCipher->Process(m_InBlock, AP4_CIPHER_BLOCK_SIZE, out, m_ChainBlock);
        AP4_CopyMemory(m_ChainBlock, out, AP4_CIPHER_BLOCK_SIZE);
        m_InBlockFullness = 0;
        if (AP4_FAILED(result)) {
            *out_size = 0;
            return result;
        }
    }
    
    return AP4_SUCCESS;
}
Ejemplo n.º 22
0
/*----------------------------------------------------------------------
|   WriteSample
+---------------------------------------------------------------------*/
static void
WriteSample(const AP4_DataBuffer& sample_data, 
            AP4_DataBuffer&       prefix, 
            unsigned int          nalu_length_size, 
            AP4_ByteStream*       output)
{
    const unsigned char* data      = sample_data.GetData();
    unsigned int         data_size = sample_data.GetDataSize();

    // detect if we have VPS/SPS/PPS and/or AUD NAL units already
    bool have_param_sets = false;
    bool have_access_unit_delimiter = false;
    while (data_size) {
        // sanity check
        if (data_size < nalu_length_size) break;
        
        // get the next NAL unit
        AP4_UI32 nalu_size;
        if (nalu_length_size == 1) {
            nalu_size = *data++;
            data_size--;
        } else if (nalu_length_size == 2) {
            nalu_size = AP4_BytesToInt16BE(data);
            data      += 2;
            data_size -= 2;
        } else if (nalu_length_size == 4) {
            nalu_size = AP4_BytesToInt32BE(data);
            data      += 4;
            data_size -= 4;
        } else {
            break;
        }
        if (nalu_size > data_size) break;
        
        unsigned int nal_unit_type = (data[0]>>1)&0x3F;
        if (nal_unit_type == AP4_HEVC_NALU_TYPE_AUD_NUT) {
            have_access_unit_delimiter = true;
        }
        if (nal_unit_type == AP4_HEVC_NALU_TYPE_VPS_NUT ||
            nal_unit_type == AP4_HEVC_NALU_TYPE_SPS_NUT ||
            nal_unit_type == AP4_HEVC_NALU_TYPE_PPS_NUT) {
            have_param_sets = true;
            break;
        }
        
        // move to the next NAL unit
        data      += nalu_size;
        data_size -= nalu_size;
    } 
    data      = sample_data.GetData();
    data_size = sample_data.GetDataSize();

    // allocate a buffer for the frame data
    AP4_DataBuffer frame_data;
    unsigned char* frame_buffer = NULL;
    
    // add a delimiter if we don't already have one
    if (data_size && !have_access_unit_delimiter) {
        AP4_Size frame_data_size = frame_data.GetDataSize();
        frame_data.SetDataSize(frame_data_size+7);
        frame_buffer = frame_data.UseData()+frame_data_size;
    
        // start of access unit
        frame_buffer[0] = 0;
        frame_buffer[1] = 0;
        frame_buffer[2] = 0;
        frame_buffer[3] = 1;
        frame_buffer[4] = AP4_HEVC_NALU_TYPE_AUD_NUT<<1;
        frame_buffer[5] = 1;
        frame_buffer[6] = 0x40; // pic_type = 2 (B,P,I)
    }
    
    // write the NAL units
    bool prefix_added = false;
    while (data_size) {
        // sanity check
        if (data_size < nalu_length_size) break;
        
        // get the next NAL unit
        AP4_UI32 nalu_size;
        if (nalu_length_size == 1) {
            nalu_size = *data++;
            data_size--;
        } else if (nalu_length_size == 2) {
            nalu_size = AP4_BytesToInt16BE(data);
            data      += 2;
            data_size -= 2;
        } else if (nalu_length_size == 4) {
            nalu_size = AP4_BytesToInt32BE(data);
            data      += 4;
            data_size -= 4;
        } else {
            break;
        }
        if (nalu_size > data_size) break;
        
        // add the prefix if needed
        if (!have_param_sets && !prefix_added && !have_access_unit_delimiter) {
            AP4_Size frame_data_size = frame_data.GetDataSize();
            frame_data.SetDataSize(frame_data_size+prefix.GetDataSize());
            frame_buffer = frame_data.UseData()+frame_data_size;
            AP4_CopyMemory(frame_buffer, prefix.GetData(), prefix.GetDataSize());
            prefix_added = true;
        }
        
        // add a start code before the NAL unit
        AP4_Size frame_data_size = frame_data.GetDataSize();
        frame_data.SetDataSize(frame_data_size+3+nalu_size);
        frame_buffer = frame_data.UseData()+frame_data_size;
        frame_buffer[0] = 0;
        frame_buffer[1] = 0;
        frame_buffer[2] = 1;
        AP4_CopyMemory(frame_buffer+3, data, nalu_size);
        
        // add the prefix if needed
        if (!have_param_sets && !prefix_added) {
            AP4_Size frame_data_size = frame_data.GetDataSize();
            frame_data.SetDataSize(frame_data_size+prefix.GetDataSize());
            frame_buffer = frame_data.UseData()+frame_data_size;
            AP4_CopyMemory(frame_buffer, prefix.GetData(), prefix.GetDataSize());
            prefix_added = true;
        }

        // move to the next NAL unit
        data      += nalu_size;
        data_size -= nalu_size;
    } 
    
    output->Write(frame_data.GetData(), frame_data.GetDataSize());
}
Ejemplo n.º 23
0
/*----------------------------------------------------------------------
|   MakeFramePrefix
+---------------------------------------------------------------------*/
static AP4_Result
MakeFramePrefix(AP4_SampleDescription* sdesc, AP4_DataBuffer& prefix, unsigned int& nalu_length_size)
{
    AP4_HevcSampleDescription* hevc_desc = AP4_DYNAMIC_CAST(AP4_HevcSampleDescription, sdesc);
    if (hevc_desc == NULL) {
        fprintf(stderr, "ERROR: track does not contain an HEVC stream\n");
        return AP4_FAILURE;
    }
    
    // extract the nalu length size
    nalu_length_size = hevc_desc->GetNaluLengthSize();

    // make the VPS/SPS/PPS prefix
    for (unsigned int i=0; i<hevc_desc->GetSequences().ItemCount(); i++) {
        const AP4_HvccAtom::Sequence& seq = hevc_desc->GetSequences()[i];
        if (seq.m_NaluType == AP4_HEVC_NALU_TYPE_VPS_NUT) {
            for (unsigned int j=0; j<seq.m_Nalus.ItemCount(); j++) {
                const AP4_DataBuffer& buffer = seq.m_Nalus[j];
                unsigned int prefix_size = prefix.GetDataSize();
                prefix.SetDataSize(prefix_size+4+buffer.GetDataSize());
                unsigned char* p = prefix.UseData()+prefix_size;
                *p++ = 0;
                *p++ = 0;
                *p++ = 0;
                *p++ = 1;
                AP4_CopyMemory(p, buffer.GetData(), buffer.GetDataSize());
            }
        }
    }

    for (unsigned int i=0; i<hevc_desc->GetSequences().ItemCount(); i++) {
        const AP4_HvccAtom::Sequence& seq = hevc_desc->GetSequences()[i];
        if (seq.m_NaluType == AP4_HEVC_NALU_TYPE_SPS_NUT) {
            for (unsigned int j=0; j<seq.m_Nalus.ItemCount(); j++) {
                const AP4_DataBuffer& buffer = seq.m_Nalus[j];
                unsigned int prefix_size = prefix.GetDataSize();
                prefix.SetDataSize(prefix_size+4+buffer.GetDataSize());
                unsigned char* p = prefix.UseData()+prefix_size;
                *p++ = 0;
                *p++ = 0;
                *p++ = 0;
                *p++ = 1;
                AP4_CopyMemory(p, buffer.GetData(), buffer.GetDataSize());
            }
        }
    }

    for (unsigned int i=0; i<hevc_desc->GetSequences().ItemCount(); i++) {
        const AP4_HvccAtom::Sequence& seq = hevc_desc->GetSequences()[i];
        if (seq.m_NaluType == AP4_HEVC_NALU_TYPE_PPS_NUT) {
            for (unsigned int j=0; j<seq.m_Nalus.ItemCount(); j++) {
                const AP4_DataBuffer& buffer = seq.m_Nalus[j];
                unsigned int prefix_size = prefix.GetDataSize();
                prefix.SetDataSize(prefix_size+4+buffer.GetDataSize());
                unsigned char* p = prefix.UseData()+prefix_size;
                *p++ = 0;
                *p++ = 0;
                *p++ = 0;
                *p++ = 1;
                AP4_CopyMemory(p, buffer.GetData(), buffer.GetDataSize());
            }
        }
    }
    
    return AP4_SUCCESS;
}
Ejemplo n.º 24
0
/*----------------------------------------------------------------------
|   WriteSample
+---------------------------------------------------------------------*/
static void
WriteSample(const AP4_DataBuffer& sample_data, 
            AP4_DataBuffer&       prefix, 
            unsigned int          nalu_length_size, 
            AP4_ByteStream*       output)
{
    const unsigned char* data      = sample_data.GetData();
    unsigned int         data_size = sample_data.GetDataSize();

    // allocate a buffer for the PES packet
    AP4_DataBuffer frame_data;
    unsigned char* frame_buffer = NULL;

    // add a delimiter if we don't already have one
    bool have_access_unit_delimiter = (data_size >  nalu_length_size) && ((data[nalu_length_size] & 0x1F) == AP4_AVC_NAL_UNIT_TYPE_ACCESS_UNIT_DELIMITER);
    if (!have_access_unit_delimiter) {
        AP4_Size frame_data_size = frame_data.GetDataSize();
        frame_data.SetDataSize(frame_data_size+6);
        frame_buffer = frame_data.UseData()+frame_data_size;
    
        // start of access unit
        frame_buffer[0] = 0;
        frame_buffer[1] = 0;
        frame_buffer[2] = 0;
        frame_buffer[3] = 1;
        frame_buffer[4] = 9;    // NAL type = Access Unit Delimiter;
        frame_buffer[5] = 0xE0; // Slice types = ANY
    }
    
    // write the NAL units
    bool prefix_added = false;
    while (data_size) {
        // sanity check
        if (data_size < nalu_length_size) break;
        
        // get the next NAL unit
        AP4_UI32 nalu_size;
        if (nalu_length_size == 1) {
            nalu_size = *data++;
            data_size--;
        } else if (nalu_length_size == 2) {
            nalu_size = AP4_BytesToInt16BE(data);
            data      += 2;
            data_size -= 2;
        } else if (nalu_length_size == 4) {
            nalu_size = AP4_BytesToInt32BE(data);
            data      += 4;
            data_size -= 4;
        } else {
            break;
        }
        if (nalu_size > data_size) break;
        
        // add the prefix if needed
        if (prefix.GetDataSize() && !prefix_added && !have_access_unit_delimiter) {
            AP4_Size frame_data_size = frame_data.GetDataSize();
            frame_data.SetDataSize(frame_data_size+prefix.GetDataSize());
            frame_buffer = frame_data.UseData()+frame_data_size;
            AP4_CopyMemory(frame_buffer, prefix.GetData(), prefix.GetDataSize());
            prefix_added = true;
        }
    
        // add a start code before the NAL unit
        AP4_Size frame_data_size = frame_data.GetDataSize();
        frame_data.SetDataSize(frame_data_size+3+nalu_size);
        frame_buffer = frame_data.UseData()+frame_data_size;
        frame_buffer[0] = 0;
        frame_buffer[1] = 0;
        frame_buffer[2] = 1;
        AP4_CopyMemory(frame_buffer+3, data, nalu_size);
        
        // add the prefix if needed
        if (prefix.GetDataSize() && !prefix_added) {
            AP4_Size frame_data_size = frame_data.GetDataSize();
            frame_data.SetDataSize(frame_data_size+prefix.GetDataSize());
            frame_buffer = frame_data.UseData()+frame_data_size;
            AP4_CopyMemory(frame_buffer, prefix.GetData(), prefix.GetDataSize());
            prefix_added = true;
        }

        // move to the next NAL unit
        data      += nalu_size;
        data_size -= nalu_size;
    } 
    
    output->Write(frame_data.GetData(), frame_data.GetDataSize());
}
Ejemplo n.º 25
0
/*----------------------------------------------------------------------
|   AP4_UuidAtom::AP4_UuidAtom
+---------------------------------------------------------------------*/
AP4_UuidAtom::AP4_UuidAtom(AP4_UI64 size, const AP4_UI08* uuid, AP4_UI08 version, AP4_UI32 flags) : 
    AP4_Atom(AP4_ATOM_TYPE_UUID, size, false, version, flags)
{
    AP4_CopyMemory(m_Uuid, uuid, 16);
}