@@ -264,6 +264,133 @@ TEST_F(AampMp4DemuxerTests, SendInitSegmentWithInvalidCodecInfo)
264264 EXPECT_FALSE (ptsError);
265265}
266266
267+ /* *
268+ * @brief Test that sending an encrypted init via normal sendSegment sets mEncryptedCapsPrimed
269+ * and subsequent clear init does not overwrite the encrypted pipeline caps.
270+ * This covers the pre-roll ad VOD scenario where the content init is fed first
271+ * so GStreamer creates an encrypted pipeline before the clear ad init arrives.
272+ */
273+ TEST_F (AampMp4DemuxerTests, EncryptedInitFollowedByClearInitSuppressesClearCaps)
274+ {
275+ const char * encInitData = " encrypted_init" ;
276+ std::vector<uint8_t > encInitBuffer (encInitData, encInitData + strlen (encInitData));
277+ const char * clearInitData = " clear_init" ;
278+ std::vector<uint8_t > clearInitBuffer (clearInitData, clearInitData + strlen (clearInitData));
279+
280+ // First call: encrypted content init (sent before pre-roll ad starts)
281+ EXPECT_CALL (*g_mockMp4Demux, Parse (_))
282+ .WillOnce (Return (true )) // encrypted init
283+ .WillOnce (Return (true )); // clear ad init
284+ EXPECT_CALL (*g_mockMp4Demux, GetSamples ())
285+ .WillOnce (Invoke ([]() { return std::vector<AampMediaSample>(); }))
286+ .WillOnce (Invoke ([]() { return std::vector<AampMediaSample>(); }));
287+ EXPECT_CALL (*g_mockMp4Demux, GetCodecInfo ())
288+ .WillOnce (Invoke ([]() {
289+ MediaCodecInfo codecInfo;
290+ codecInfo.mCodecFormat = GST_FORMAT_VIDEO_ES_H264 ;
291+ codecInfo.mIsEncrypted = true ;
292+ return codecInfo;
293+ }))
294+ .WillOnce (Invoke ([]() {
295+ MediaCodecInfo codecInfo;
296+ codecInfo.mCodecFormat = GST_FORMAT_VIDEO_ES_H264 ;
297+ codecInfo.mIsEncrypted = false ;
298+ return codecInfo;
299+ }));
300+ // SetStreamCaps must be called exactly once (for the encrypted init only)
301+ EXPECT_CALL (*g_mockPrivateInstanceAAMP,
302+ SetStreamCaps (eMEDIATYPE_VIDEO, _)).Times (1 );
303+ EXPECT_CALL (*g_mockPrivateInstanceAAMP, SendStreamTransfer (_, _)).Times (0 );
304+
305+ bool ptsError = false ;
306+ // Content init arrives first via CacheFragment path
307+ EXPECT_TRUE (mDemuxer ->sendSegment (std::move (encInitBuffer), 0.0 , 0.0 , 0.0 ,
308+ false , true , nullptr , ptsError));
309+ EXPECT_FALSE (ptsError);
310+
311+ // Ad init arrives — clear caps must be suppressed
312+ EXPECT_TRUE (mDemuxer ->sendSegment (std::move (clearInitBuffer), 0.0 , 0.0 , 0.0 ,
313+ false , true , nullptr , ptsError));
314+ EXPECT_FALSE (ptsError);
315+ }
316+
317+ /* *
318+ * @brief Test that reset() clears the encrypted caps primed flag so a subsequent
319+ * init can update the pipeline normally (content restart after ad).
320+ */
321+ TEST_F (AampMp4DemuxerTests, ResetClearsEncryptedCapsPrimedFlag)
322+ {
323+ const char * encInitData = " encrypted_init" ;
324+ std::vector<uint8_t > encInitBuffer (encInitData, encInitData + strlen (encInitData));
325+ const char * contentInitData = " content_init_restart" ;
326+ std::vector<uint8_t > contentRestartBuffer (
327+ contentInitData, contentInitData + strlen (contentInitData));
328+
329+ EXPECT_CALL (*g_mockMp4Demux, Parse (_))
330+ .WillOnce (Return (true )) // encrypted init
331+ .WillOnce (Return (true )); // content init after reset
332+ EXPECT_CALL (*g_mockMp4Demux, GetSamples ())
333+ .WillOnce (Invoke ([]() { return std::vector<AampMediaSample>(); }))
334+ .WillOnce (Invoke ([]() { return std::vector<AampMediaSample>(); }));
335+ EXPECT_CALL (*g_mockMp4Demux, GetCodecInfo ())
336+ .WillOnce (Invoke ([]() {
337+ MediaCodecInfo codecInfo;
338+ codecInfo.mCodecFormat = GST_FORMAT_VIDEO_ES_H264 ;
339+ codecInfo.mIsEncrypted = true ;
340+ return codecInfo;
341+ }))
342+ .WillOnce (Invoke ([]() {
343+ MediaCodecInfo codecInfo;
344+ codecInfo.mCodecFormat = GST_FORMAT_VIDEO_ES_H264 ;
345+ codecInfo.mIsEncrypted = true ;
346+ return codecInfo;
347+ }));
348+ // SetStreamCaps called for both: first priming, then content restart after reset
349+ EXPECT_CALL (*g_mockPrivateInstanceAAMP,
350+ SetStreamCaps (eMEDIATYPE_VIDEO, _)).Times (2 );
351+ EXPECT_CALL (*g_mockPrivateInstanceAAMP, SendStreamTransfer (_, _)).Times (0 );
352+
353+ bool ptsError = false ;
354+ EXPECT_TRUE (mDemuxer ->sendSegment (std::move (encInitBuffer), 0.0 , 0.0 , 0.0 ,
355+ false , true , nullptr , ptsError));
356+
357+ // reset() is called when content playback is restarted (ad ends)
358+ mDemuxer ->reset ();
359+
360+ // Content init re-sent by fragment collector — must not be suppressed
361+ EXPECT_TRUE (mDemuxer ->sendSegment (std::move (contentRestartBuffer), 0.0 , 0.0 , 0.0 ,
362+ false , true , nullptr , ptsError));
363+ EXPECT_FALSE (ptsError);
364+ }
365+
366+ /* *
367+ * @brief Test that a clear init sent without prior encrypted init proceeds normally.
368+ */
369+ TEST_F (AampMp4DemuxerTests, ClearInitWithoutPriorEncryptedInitSetsClearCaps)
370+ {
371+ const char * clearInitData = " clear_init" ;
372+ std::vector<uint8_t > clearInitBuffer (clearInitData, clearInitData + strlen (clearInitData));
373+
374+ EXPECT_CALL (*g_mockMp4Demux, Parse (_)).WillOnce (Return (true ));
375+ EXPECT_CALL (*g_mockMp4Demux, GetSamples ())
376+ .WillOnce (Invoke ([]() { return std::vector<AampMediaSample>(); }));
377+ EXPECT_CALL (*g_mockMp4Demux, GetCodecInfo ())
378+ .WillOnce (Invoke ([]() {
379+ MediaCodecInfo codecInfo;
380+ codecInfo.mCodecFormat = GST_FORMAT_VIDEO_ES_H264 ;
381+ codecInfo.mIsEncrypted = false ;
382+ return codecInfo;
383+ }));
384+ EXPECT_CALL (*g_mockPrivateInstanceAAMP,
385+ SetStreamCaps (eMEDIATYPE_VIDEO, _)).Times (1 );
386+ EXPECT_CALL (*g_mockPrivateInstanceAAMP, SendStreamTransfer (_, _)).Times (0 );
387+
388+ bool ptsError = false ;
389+ EXPECT_TRUE (mDemuxer ->sendSegment (std::move (clearInitBuffer), 0.0 , 0.0 , 0.0 ,
390+ false , true , nullptr , ptsError));
391+ EXPECT_FALSE (ptsError);
392+ }
393+
267394/* *
268395 * @brief Test sendSegment with parse failure
269396 */
0 commit comments