Skip to content

Conversation

zsiec
Copy link
Member

@zsiec zsiec commented Jun 14, 2019

We're opening this PR as a draft and have yet to write tests. We are looking for feedback from the community on this approach. We've moved the Bitmovin provider from a single file to a new structure we think is more suited to extend, test, and maintain.

Our general approach here was to (1) abstract away the details of managing presets from the global scope and instead localize configurations for specific codecs/formats in their own files, with their logic accessible via interfaces, (2) do the same for generation of output "container"s, and (3) follow a similar model for enriching the JobStatus report with output information.

We are using the new Bitmovin Go SDK found here: https://github.com/bitmovin/bitmovin-api-sdk-go - any help from the folks at Bitmovin to CR this and ensure we're using this alpha-version SDK as intended would be very welcome.

@codecov-io
Copy link

codecov-io commented Jun 15, 2019

Codecov Report

Merging #210 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #210   +/-   ##
=======================================
  Coverage   78.62%   78.62%           
=======================================
  Files          29       29           
  Lines        2914     2914           
=======================================
  Hits         2291     2291           
  Misses        372      372           
  Partials      251      251

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 986b203...0e26b5e. Read the comment docs.

@zsiec
Copy link
Member Author

zsiec commented Jun 15, 2019

There is currently one known issue with the new SDK, filed here: bitmovin/bitmovin-api-sdk-go#1

Copy link

@jonathanhperry jonathanhperry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall all the object usage looks correct

@@ -7,6 +7,7 @@ import (
"github.com/NYTimes/gizmo/server"
"github.com/NYTimes/video-transcoding-api/config"
_ "github.com/NYTimes/video-transcoding-api/provider/bitmovin"
_ "github.com/NYTimes/video-transcoding-api/provider/bitmovinnewsdk"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would perhaps suggest using bitmovinopenapi if a new provider name is required

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, makes sense, the name I chose was meant to be a placeholder until there was clarity on if this replaced the current provider or will be available in addition to it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this using a different API or just a different SDK?

If it's a different SDK or a new API that's already GA, let's have this replace the old provider 😁

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the same API, but a new SDK (although the SDK is still in alpha)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should be fine, let's do it! 😬

if err != nil {
return model.H264VideoConfiguration{}, err
}
cfg.MaxGop = gopSize // TODO: investigate this to ensure it respects preset gop mode and size

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MaxGop is correct to use when defining the GOP in frames

vodHLSManifests = []model.ManifestResource{{ManifestId: manifestID}}
}

encResp, err := p.api.Encoding.Encodings.Start(enc.Id, model.StartEncodingRequest{VodHlsManifests: vodHLSManifests})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for using the VodHlsManifests to start the HLS creation

Copy link
Member Author

@zsiec zsiec Jun 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the 👍 belongs to @jamescyeh as this is based off code originally written by him :)

return nil, errBitmovinInvalidConfig
}

api, err := bitmovin.NewBitmovinApi(func(apiClient *common.ApiClient) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend adding support for passing in an organization id. This enables a customer to use their personal API key to kick off encodes, but the encodes themselves are stored within an Organization's context, which allows colleagues to see the same encodes without logging into your personal user.

e.g.

apiClient.TenantOrgId = cfg.Bitmovin.OrganizationId

This is optional and can be left undefined.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know, I'll add this.

}

func h264ConfigFrom(preset db.Preset, customData *map[string]map[string]interface{}) (model.H264VideoConfiguration, error) {
cfg := model.H264VideoConfiguration{}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've added support for Preset Configurations that can be set on a codec. These are presets to set low-level codec properties (reference frames, b frames, etc) based on Bitmovin's recommendations. Preset enum: https://github.com/bitmovin/bitmovin-api-sdk-go/blob/master/model/preset_configuration.go and their definitions: https://bitmovin.com/docs/encoding/tutorials/how-to-optimize-your-h264-codec-configuration-for-different-use-cases.

May be useful to expose this in a job configuration.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those look useful, I'll have to check to see how that best fits into the project structure as it sits today, and see what kinds of options are best for exposing special preset functionality provided only in a single or handful of providers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thinking out loud, I kind of see this happening more often as we add support for Per-title Encoding, 10 bits, etc. I wonder if we should have something like a providerConfig being carried around for the specific parameters of a provider so when triggering a job we could validate if the providerConfig is supported or not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that falls in line with my thinking as well. We already have that Capabilities interface function, that idea could be extended and given more thought.

return model.AacAudioConfiguration{
Name: fmt.Sprintf("aac_%s_%.0f", bitrate, defaultAACSampleRate),
Bitrate: &convertedBitrate,
Rate: floatToPtr(defaultAACSampleRate),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From Bitmovin's side, are there any plans to override the JSON marshalling of each of the models, bypassing any confusion of zero values, and things getting ignored? With code generation, it may be something that could be relatively easy.

Copy link
Collaborator

@fsouza fsouza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sharing some notes, I still want to take another look and may have more notes later today or tomorrow 😬

Thanks for working on this! :D

@@ -7,6 +7,7 @@ import (
"github.com/NYTimes/gizmo/server"
"github.com/NYTimes/video-transcoding-api/config"
_ "github.com/NYTimes/video-transcoding-api/provider/bitmovin"
_ "github.com/NYTimes/video-transcoding-api/provider/bitmovinnewsdk"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this using a different API or just a different SDK?

If it's a different SDK or a new API that's already GA, let's have this replace the old provider 😁

)

// Just to double check the interface is properly implemented
var _ provider.TranscodingProvider = (*bitmovinProvider)(nil)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this to a test once we have a test suite, though since the factory returns *bitmovinProvider + we're registering the factory with provider.Register, this check isn't strictly necessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good, will remove


const (
defaultVorbisSampleRate float64 = 48000
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: since there's only one constant here, let's not use a block. Also, the type is not needed:

const defaultVorbisSampleRate = 48000

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 I'll update

Copy link
Collaborator

@fsouza fsouza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good. Thank you very much for splitting it into multiple files. I don't know how I feel about having multiple packages though, could we have everything in a single package?

Or, if we chose to go the multi-packages route, could we make the helper packages internal? (I've been thinking about making provider packages internal too, just to guarantee no one can depend directly on them).

What do you think?

import "errors"

// CustomData holds data to set on encodings and configurations to hold relationship state
type CustomData *map[string]map[string]interface{}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh just noticed this. Does it need to be a pointer?

Suggested change
type CustomData *map[string]map[string]interface{}
type CustomData map[string]map[string]interface{}

Or could we have some kind of structured data on our side that then gets marshaled into a JSON-object that looks arbitrary in the bitmovin API? Something like:

type CustomData struct {
  Audio struct {
    ID string `json:"id"`
  } `json:"audio"`
  Container struct {
    Name string `json:"name"`
  } `json:"container"`
  Manifest struct {
    ID string `json:"id"`
  } `json:"manifest"`
}

(not necessarily with inline structs, I'm just being lazy here 🙈 )

@zsiec zsiec force-pushed the new-bitmovin-provider branch from dabe57d to 0e26b5e Compare June 26, 2019 14:52
@zsiec zsiec closed this Sep 15, 2019
@zsiec zsiec deleted the new-bitmovin-provider branch September 15, 2019 17:12
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.

6 participants