androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.53k stars 372 forks source link

SCTE-35 : what's the better way to play replacement ads #490

Open cdongieux opened 1 year ago

cdongieux commented 1 year ago

Hi,

I'm working on SCTE-35 implementation on our app. We play a live TS stream containing SCTE-35 metadata, I'm able to parse it and I know when an ad break starts/ends, and when a new ad is playing. I made a PoC with 2 ExoPlayer instances: 1 for the original stream and 1 for playing SCTE-35 ads. I'm wondering what's the best way to play SCTE-35 ads replacing ads from the original stream.

Do you have any advice about that? Or would a single instance of ExoPlayer be able to play the original stream and play ads in parallel?

Best regards.

marcbaechinger commented 1 year ago

The IMA extension does client-side ad insertion with a single player and preloads ads like in a playlist so that the transition from content to ad stream and back is seamless.

The extension uses the AdsMediaSource for this that is part of ExoPlayer core. My recommendation would be that you create and maintain an AdPlaybackState that you then pass to AdsMediaSource.onAdPlaybckState(AdPlaybackState) when it changes.

Please also see https://developer.android.com/guide/topics/media/exoplayer/ad-insertionk

tonihei commented 1 year ago

I think the preferred way to signal this type of metadata in HLS is to actually make it part of the playlist. We don't support this yet, but it sounds that's the kind of feature you are looking for? See #10992.

marcbaechinger commented 1 year ago

Oh, yes, Thanks Toni. I missed the live TS stream part of the question.

cdongieux commented 1 year ago

Well, actually it's a live TS stream from RTSP.

As I said in the OP, SCTE-35 metadata parsing is not the problem. About IMA and/or IMA extension, I don't think this could work. Here is an ad server call response extract:

<VAST version="3.0" daiversion="1.0">
    <Ad id="70924815.139820984207616" sequence="2">
        <InLine>
            <AdSystem version="1.0">FreeWheel</AdSystem>
            <AdTitle>TEST_ADRESSABLE_VIDEO_GLOBAL_20s</AdTitle>
            <Error>
                <![CDATA[ https://adserver.com/daitrackingevents/739a80b608b342354f64b087645f6831-12911842_error?dai=1 ]]>
            </Error>
            <Impression>
                <![CDATA[ https://adserver.com/daitrackingevents/739a80b608b342354f64b087645f6831-12911842_impression?dai=1 ]]>
            </Impression>
            <Creatives>
                <Creative>
                    <Linear>
                        <Duration>00:00:20</Duration>
                        <TrackingEvents>
                            <Tracking event="firstQuartile">
                                <![CDATA[ https://adserver.com/daitrackingevents/739a80b608b342354f64b087645f6831-12911842_firstQuartile?dai=1 ]]>
                            </Tracking>
                            <Tracking event="midpoint">
                                <![CDATA[ https://adserver.com/daitrackingevents/739a80b608b342354f64b087645f6831-12911842_midpoint?dai=1 ]]>
                            </Tracking>
                            <Tracking event="thirdQuartile">
                                <![CDATA[ https://adserver.com/daitrackingevents/739a80b608b342354f64b087645f6831-12911842_thirdQuartile?dai=1 ]]>
                            </Tracking>
                            <Tracking event="complete">
                                <![CDATA[ https://adserver.com/daitrackingevents/739a80b608b342354f64b087645f6831-12911842_complete?dai=1 ]]>
                            </Tracking>
                        </TrackingEvents>
                        <MediaFiles>
                            <MediaFile delivery="progressive" type="video/mp4" bitrate="3171" width="1280" height="720">
                                <![CDATA[ http://adserver.com/1492605.ts ]]>
                            </MediaFile>
                        </MediaFiles>
                    </Linear>
                </Creative>
            </Creatives>
        </InLine>
    </Ad>
    <Ad id="70924821.140435887586816" sequence="9">
        <InLine>
            <AdSystem version="1.0">FreeWheel</AdSystem>
            <AdTitle>TEST_ADRESSABLE_VIDEO_GLOBAL_30s_3</AdTitle>
            <Error>
                <![CDATA[ https://adserver.com/daitrackingevents/a77591648272928b3d96f2f7b9914425-12945218_error?dai=1 ]]>
            </Error>
            <Impression>
                <![CDATA[ https://adserver.com/daitrackingevents/a77591648272928b3d96f2f7b9914425-12945218_impression?dai=1 ]]>
            </Impression>
            <Creatives>
                <Creative>
                    <Linear>
                        <Duration>00:00:30</Duration>
                        <TrackingEvents>
                            <Tracking event="firstQuartile">
                                <![CDATA[ https://adserver.com/daitrackingevents/a77591648272928b3d96f2f7b9914425-12945218_firstQuartile?dai=1 ]]>
                            </Tracking>
                            <Tracking event="midpoint">
                                <![CDATA[ https://adserver.com/daitrackingevents/a77591648272928b3d96f2f7b9914425-12945218_midpoint?dai=1 ]]>
                            </Tracking>
                            <Tracking event="thirdQuartile">
                                <![CDATA[ https://adserver.com/daitrackingevents/a77591648272928b3d96f2f7b9914425-12945218_thirdQuartile?dai=1 ]]>
                            </Tracking>
                            <Tracking event="complete">
                                <![CDATA[ https://adserver.com/daitrackingevents/a77591648272928b3d96f2f7b9914425-12945218_complete?dai=1 ]]>
                            </Tracking>
                        </TrackingEvents>
                        <MediaFiles>
                            <MediaFile delivery="progressive" type="video/mp4" bitrate="3171" width="1280" height="720">
                                <![CDATA[ http://adserver.com/1494367.ts ]]>
                            </MediaFile>
                        </MediaFiles>
                    </Linear>
                </Creative>
            </Creatives>
        </InLine>
    </Ad>
</VAST>

There is no way for IMA to know the right time to play these ads.

rahulfancode commented 9 months ago

@cdongieux Hi, We are also working on the same problem, Could you please help me with the parsing logic and how to detect ad break starts/ends

https://www.vmax.com/ is a third party provider it has a solution to play ads during SCTE breaks

cdongieux commented 9 months ago

Hi @rahulfancode, what kind of input data do you have?

In my case, there is SCTE-35 metadata in the TS stream. The current implementation in ExoPlayer only supports SCTE-35 commands and lacks support of SCTE-35 splice descriptors (see SCTE-35 spec, section 10), so I had to implement it (easy part). All information about ad breaks is in these descriptors.

Then I implemented a Player.Listener listening for Metadata in the onMetadata() callback, which helps to control a second instance of ExoPlayer to play ads at the right moment.