/*---------------------------------------------------------------------- | NPT_DateTime::ToString +---------------------------------------------------------------------*/ NPT_String NPT_DateTime::ToString(Format format, NPT_Flags flags) const { NPT_String result; if (NPT_FAILED(CheckDate(*this))) return result; switch (format) { case FORMAT_W3C: AppendNumber(result, m_Year, 4); result += '-'; AppendNumber(result, m_Month, 2); result += '-'; AppendNumber(result, m_Day, 2); result += 'T'; AppendNumber(result, m_Hours, 2); result += ':'; AppendNumber(result, m_Minutes, 2); result += ':'; AppendNumber(result, m_Seconds, 2); if (flags & FLAG_EMIT_FRACTION) { result += '.'; if (flags & FLAG_EXTENDED_PRECISION) { // nanoseconds precision AppendNumber(result, m_NanoSeconds, 9); } else { // only miliseconds precision AppendNumber(result, m_NanoSeconds/1000000, 3); } } if (m_TimeZone) { NPT_UInt32 tz; if (m_TimeZone > 0) { result += '+'; tz = m_TimeZone; } else { result += '-'; tz = -m_TimeZone; } AppendNumber(result, tz/60, 2); result += ':'; AppendNumber(result, tz%60, 2); } else { result += 'Z'; } break; case FORMAT_ANSI: { // compute the number of days elapsed since 1900 NPT_UInt32 days = ElapsedDaysSince1900(*this); // format the result result.SetLength(24); NPT_FormatString(result.UseChars(), result.GetLength()+1, "%.3s %.3s%3d %.2d:%.2d:%.2d %d", NPT_TIME_DAYS_SHORT[(days+1)%7], NPT_TIME_MONTHS[m_Month-1], m_Day, m_Hours, m_Minutes, m_Seconds, m_Year); break; } case FORMAT_RFC_1036: case FORMAT_RFC_1123: { // compute the number of days elapsed since 1900 NPT_UInt32 days = ElapsedDaysSince1900(*this); if (format == FORMAT_RFC_1036) { result += NPT_TIME_DAYS_LONG[(days+1)%7]; result += ", "; AppendNumber(result, m_Day, 2); result += '-'; result += NPT_TIME_MONTHS[m_Month-1]; result += '-'; AppendNumber(result, m_Year%100, 2); } else { result += NPT_TIME_DAYS_SHORT[(days+1)%7]; result += ", "; AppendNumber(result, m_Day, 2); result += ' '; result += NPT_TIME_MONTHS[m_Month-1]; result += ' '; AppendNumber(result, m_Year, 4); } result += ' '; AppendNumber(result, m_Hours, 2); result += ':'; AppendNumber(result, m_Minutes, 2); result += ':'; AppendNumber(result, m_Seconds, 2); if (m_TimeZone) { if (m_TimeZone > 0) { result += " +"; AppendNumber(result, m_TimeZone/60, 2); AppendNumber(result, m_TimeZone%60, 2); } else { result += " -"; AppendNumber(result, -m_TimeZone/60, 2); AppendNumber(result, -m_TimeZone%60, 2); } } else { result += " GMT"; } break; } } return result; }
/*---------------------------------------------------------------------- | Mp4ParserOutput_ProcessCryptoInfo +---------------------------------------------------------------------*/ static BLT_Result Mp4ParserOutput_ProcessCryptoInfo(Mp4ParserOutput* self, AP4_SampleDescription*& sample_desc) { // check if the track is encrypted if (sample_desc->GetType() == AP4_SampleDescription::TYPE_PROTECTED) { ATX_LOG_FINE("track is encrypted"); AP4_ProtectedSampleDescription* prot_desc = dynamic_cast<AP4_ProtectedSampleDescription*>(sample_desc); if (prot_desc == NULL) { ATX_LOG_FINE("unable to obtain cipher info"); return BLT_ERROR_INVALID_MEDIA_FORMAT; } // obtain the key manager if (self->parser->key_manager == NULL) { ATX_Properties* properties = NULL; if (BLT_SUCCEEDED(BLT_Core_GetProperties(ATX_BASE(self->parser, BLT_BaseMediaNode).core, &properties))) { ATX_PropertyValue value; if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, BLT_KEY_MANAGER_PROPERTY, &value))) { if (value.type == ATX_PROPERTY_VALUE_TYPE_POINTER) { self->parser->key_manager = (BLT_KeyManager*)value.data.pointer; } } else { ATX_LOG_FINE("no key manager"); } } } if (self->parser->key_manager == NULL) return BLT_ERROR_NO_MEDIA_KEY; // check if we need to use a cipher factory if (self->parser->cipher_factory == NULL) { ATX_Properties* properties = NULL; if (BLT_SUCCEEDED(BLT_Core_GetProperties(ATX_BASE(self->parser, BLT_BaseMediaNode).core, &properties))) { ATX_PropertyValue value; if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, BLT_CIPHER_FACTORY_PROPERTY, &value))) { if (value.type == ATX_PROPERTY_VALUE_TYPE_POINTER) { self->parser->cipher_factory = new BLT_Ap4CipherFactoryAdapter((BLT_CipherFactory*)value.data.pointer); } } } } // figure out the content ID for this track // TODO: support different content ID schemes // for now, we just make up a content ID based on the track ID char content_id[32]; NPT_FormatString(content_id, sizeof(content_id), "@track.%d", self->track->GetId()); // get the key for this content unsigned int key_size = 256; NPT_DataBuffer key(key_size); BLT_Result result = BLT_KeyManager_GetKeyByName(self->parser->key_manager, content_id, key.UseData(), &key_size); if (result == ATX_ERROR_NOT_ENOUGH_SPACE) { key.SetDataSize(key_size); result = BLT_KeyManager_GetKeyByName(self->parser->key_manager, content_id, key.UseData(), &key_size); } if (BLT_FAILED(result)) return BLT_ERROR_NO_MEDIA_KEY; key.SetDataSize(key_size); delete self->sample_decrypter; self->sample_decrypter = AP4_SampleDecrypter::Create(prot_desc, key.GetData(), key_size, self->parser->cipher_factory); if (self->sample_decrypter == NULL) { ATX_LOG_FINE("unable to create decrypter"); return BLT_ERROR_CRYPTO_FAILURE; } // switch to the original sample description sample_desc = prot_desc->GetOriginalSampleDescription(); } return BLT_SUCCESS; }