Skip to content

feat(rendering): allow multiformat (banner + video) on BannerView - #1000

Open
nsp37 wants to merge 3 commits into
prebid:masterfrom
nsp37:feat/rendering-bannerview-multiformat
Open

nsp37 wants to merge 3 commits into
prebid:masterfrom
nsp37:feat/rendering-bannerview-multiformat

Conversation

@nsp37

@nsp37 nsp37 commented Aug 29, 2026

Copy link
Copy Markdown

Intent to implement

#999

Problem

The rendering BannerView can only request a single format:

  • its constructors set AdFormat.BANNER, and
  • setVideoPlacementType(...) calls adUnitConfig.setAdFormat(VAST), which clears banner → video-only.

So a rendering-API banner placement can't let banner and outstream video compete on one impression — unlike InterstitialAdUnit(context, configId, EnumSet.of(AdUnitFormat.BANNER, AdUnitFormat.VIDEO)) and the original API (#610). Requested for banner in #621, where only interstitial was addressed.

Change

Add two passthroughs to BannerView, delegating to the already-public AdUnitConfiguration API (the same one InterstitialAdUnit uses):

public void setAdUnitFormats(EnumSet<AdUnitFormat> adUnitFormats)  // -> adUnitConfig.setAdUnitFormats(...)
public void setVideoParameters(VideoParameters videoParameters)    // -> adUnitConfig.setVideoParameters(...)

Why no renderer changes are needed

BannerView → DisplayView → PrebidRenderer.createBannerAdView → PrebidDisplayView, and PrebidDisplayView already branches on BidResponse#isVideo() (VideoView for VAST, banner otherwise). Only the request-side format set was gated; the render path already handles the winning format.

Notes


Disclosure: implemented with AI assistance (Claude Code); reviewed and submitted by @nsp37.

🤖 Generated with Claude Code

The rendering BannerView could only request a single format: its constructors
set AdFormat.BANNER and setVideoPlacementType() calls setAdFormat(VAST), which
clears banner (video-only). So a rendering-API banner placement couldn't let
banner and outstream video compete on one impression — unlike InterstitialAdUnit
(EnumSet<AdUnitFormat>) and the original API.

Add setAdUnitFormats(EnumSet<AdUnitFormat>) and setVideoParameters(...) to
BannerView, delegating to the already-public AdUnitConfiguration API. No renderer
changes: BannerView -> DisplayView -> PrebidRenderer.createBannerAdView ->
PrebidDisplayView already branches on BidResponse#isVideo() (VideoView vs banner);
only the request-side format was gated.

Intent to implement: prebid#999

Co-authored-by: Claude <noreply@anthropic.com>
Addresses review feedback: setVideoParameters() on a rendering BannerView was
inert beyond video.w/h. BasicParameterBuilder.setVideoImpValues() reads the full
VideoParameters (mimes, protocols, playbackmethod, api, plcmt, placement,
durations, bitrates, skippable, battr) only inside if (isOriginalAdUnit()) — a
flag no rendering-API class sets — so a multiformat BannerView's outstream imp
shipped hardcoded defaults and placement=INTERSTITIAL.

Relax the gate to also read VideoParameters when explicitly set:
  if (adConfiguration.isOriginalAdUnit() || adConfiguration.getVideoParameters() != null)

Guarded — rendering units that never call setVideoParameters keep the original
default branch, so existing behavior is unchanged. Also resolves the placement
concern: params carry placement/plcmt, so no separate setter is needed.
isOriginalAdUnit is intentionally not flipped (it drives more than video imps).
@nsp37

nsp37 commented Sep 2, 2026

Copy link
Copy Markdown
Author

Thanks for the thorough review — both points were spot-on. Pushed a follow-up commit taking option (a).

setVideoParameters() inert beyond ad size: relaxed the gate in BasicParameterBuilder.setVideoImpValues() so it reads VideoParameters on the rendering path too, not just when isOriginalAdUnit():

if (adConfiguration.isOriginalAdUnit() || adConfiguration.getVideoParameters() != null)

It's guarded on getVideoParameters() != null, so rendering units that never call setVideoParameters keep the existing default branch untouched — no behavior change for current rendering interstitials. I deliberately did not flip isOriginalAdUnit since it drives far more than video imp building.

Non-interstitial video.placement: this is resolved by the same change rather than a new setter — the caller's VideoParameters carry placement/plcmt, which the now-reachable branch reads, so a multiformat BannerView no longer falls back to PlacementType.INTERSTITIAL. That avoids the setVideoPlacementType() conflict you noted (it collapses formats to VAST-only, so it can't combine with setAdUnitFormats anyway).

Happy to add tests or adjust the approach (e.g. a dedicated non-original branch instead of the ||) if you'd prefer.

testRenderingApiVideoParameters_{interstitial,nonInterstitial}_full both
assert video.placement == 5 (Interstitial) — the value the rendering path
always hardcoded before this PR's fix. Both tests call
configuration.setVideoParameters(createFullVideoParameters()), which sets
placement = InBanner (2) — exactly the value the ORIGINAL-API path already
asserts for the same input (see the existing assertEquals(new Integer(2), ...)
a few tests up). With the isOriginalAdUnit() || getVideoParameters() != null
gate this PR adds, the rendering path now reads that same explicit value
instead of defaulting to Interstitial, so these two fixtures need updating to
match — the code change is correct, the tests were stale.

Confirmed testRenderingApiVideoParameters_nonInterstitial_empty (no
VideoParameters set) is unaffected and correctly keeps placement == 5: that
test's config has getVideoParameters() == null, so the new gate still takes
the pre-existing default branch for it.

Could not run this locally (AGP requires JDK 17; only JDK 11 available in
this environment) — verified the expected value by cross-referencing the
already-passing original-API assertion for the identical input, not by
executing the suite. Please confirm on CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant