diff --git a/provider/zencoder/zencoder.go b/provider/zencoder/zencoder.go index 5cd8afbe..3e87beca 100644 --- a/provider/zencoder/zencoder.go +++ b/provider/zencoder/zencoder.go @@ -99,31 +99,39 @@ func (z *zencoderProvider) buildOutputs(job *db.Job) ([]*zencoder.OutputSettings if hlsOutputs > 0 { outputsWithHLS := make([]*zencoder.OutputSettings, len(zencoderOutputs)+1) copy(outputsWithHLS, zencoderOutputs) - hlsPlaylist := z.buildHLSPlaylist(zencoderOutputs, hlsOutputs, job.StreamingParams) + hlsPlaylist, err := z.buildHLSPlaylist(zencoderOutputs, hlsOutputs, job) + if err != nil { + return nil, fmt.Errorf("Error building hls master playlist: %s", err.Error()) + } outputsWithHLS[len(zencoderOutputs)] = &hlsPlaylist zencoderOutputs = outputsWithHLS } return zencoderOutputs, nil } -func (z *zencoderProvider) buildHLSPlaylist(outputs []*zencoder.OutputSettings, hlsOutputs int, streamingParams db.StreamingParams) zencoder.OutputSettings { +func (z *zencoderProvider) buildHLSPlaylist(outputs []*zencoder.OutputSettings, hlsOutputs int, job *db.Job) (zencoder.OutputSettings, error) { + destinationURL, err := url.Parse(z.config.Zencoder.Destination) + if err != nil { + return zencoder.OutputSettings{}, fmt.Errorf("error parsing destination (%q)", z.config.Zencoder.Destination) + } + destinationURL.Path = path.Join(destinationURL.Path, job.ID) output := zencoder.OutputSettings{ - BaseUrl: outputs[0].BaseUrl, - Filename: streamingParams.PlaylistFileName, + BaseUrl: destinationURL.String(), + Filename: job.StreamingParams.PlaylistFileName, Type: "playlist", } streams := make([]*zencoder.StreamSettings, 0, hlsOutputs) for _, output := range outputs { if output.Format == "ts" { stream := zencoder.StreamSettings{ - Path: output.Filename, + Path: path.Join(output.Label, output.Filename), Source: output.Label, } streams = append(streams, &stream) } } output.Streams = streams - return output + return output, nil } func (z *zencoderProvider) getResolution(preset db.Preset) (int32, int32) { @@ -146,12 +154,6 @@ func (z *zencoderProvider) buildOutput(job *db.Job, preset db.Preset, filename s AudioCodec: preset.Audio.Codec, Filename: filename, } - destinationURL, err := url.Parse(z.config.Zencoder.Destination) - if err != nil { - return zencoder.OutputSettings{}, fmt.Errorf("error parsing destination (%q)", z.config.Zencoder.Destination) - } - destinationURL.Path = path.Join(destinationURL.Path, job.ID) + "/" - zencoderOutput.BaseUrl = destinationURL.String() zencoderOutput.Width, zencoderOutput.Height = z.getResolution(preset) videoBitrate, err := strconv.ParseInt(preset.Video.Bitrate, 10, 32) if err != nil { @@ -181,16 +183,22 @@ func (z *zencoderProvider) buildOutput(job *db.Job, preset db.Preset, filename s if preset.RateControl == "CBR" { zencoderOutput.ConstantBitrate = true } + destinationURL, err := url.Parse(z.config.Zencoder.Destination) + if err != nil { + return zencoder.OutputSettings{}, fmt.Errorf("error parsing destination (%q)", z.config.Zencoder.Destination) + } + destinationURL.Path = path.Join(destinationURL.Path, job.ID) if preset.Container == "m3u8" { zencoderOutput.Type = "segmented" zencoderOutput.Format = "ts" zencoderOutput.SegmentSeconds = int32(job.StreamingParams.SegmentDuration) zencoderOutput.PrepareForSegmenting = job.StreamingParams.Protocol zencoderOutput.HLSOptimizedTS = true + destinationURL.Path = path.Join(destinationURL.Path, "hls", zencoderOutput.Label) } else { zencoderOutput.Format = preset.Container } - + zencoderOutput.BaseUrl = destinationURL.String() zencoderOutput.Deinterlace = "on" return zencoderOutput, nil } diff --git a/provider/zencoder/zencoder_test.go b/provider/zencoder/zencoder_test.go index 70b7e9ec..94081d99 100644 --- a/provider/zencoder/zencoder_test.go +++ b/provider/zencoder/zencoder_test.go @@ -347,7 +347,7 @@ func TestZencoderBuildOutputs(t *testing.T) { "video_codec": "h264", "h264_level": "3.1", "h264_profile": "main", - "base_url": "https://log:pass@s3.here.com/1234567890/", + "base_url": "https://log:pass@s3.here.com/1234567890", "keyframe_interval": float64(90), "width": float64(720), "height": float64(1080), @@ -406,7 +406,7 @@ func TestZencoderBuildOutputs(t *testing.T) { "video_codec": "h264", "h264_level": "3.1", "h264_profile": "main", - "base_url": "https://log:pass@s3.here.com/1234567890/", + "base_url": "https://log:pass@s3.here.com/1234567890/hls/preset1", "keyframe_interval": float64(90), "width": float64(720), "height": float64(1080), @@ -427,7 +427,7 @@ func TestZencoderBuildOutputs(t *testing.T) { "video_codec": "h264", "h264_level": "3.1", "h264_profile": "main", - "base_url": "https://log:pass@s3.here.com/1234567890/", + "base_url": "https://log:pass@s3.here.com/1234567890/hls/preset2", "keyframe_interval": float64(90), "width": float64(720), "height": float64(1080), @@ -444,12 +444,12 @@ func TestZencoderBuildOutputs(t *testing.T) { "prepare_for_segmenting": "hls", }, { - "base_url": "https://log:pass@s3.here.com/1234567890/", + "base_url": "https://log:pass@s3.here.com/1234567890", "filename": "hls/playlist.m3u8", "type": "playlist", "streams": []interface{}{ - map[string]interface{}{"source": "preset1", "path": "output1.m3u8"}, - map[string]interface{}{"source": "preset2", "path": "output2.m3u8"}, + map[string]interface{}{"source": "preset1", "path": "preset1/output1.m3u8"}, + map[string]interface{}{"source": "preset2", "path": "preset2/output2.m3u8"}, }, }, }, @@ -479,7 +479,7 @@ func TestZencoderBuildOutputs(t *testing.T) { } if !reflect.DeepEqual(result, test.Expected) { pretty.Fdiff(os.Stderr, test.Expected, result) - t.Errorf("Failed to build outputs. Want:\n %#v\n Got\n %#v", test.Expected, result) + t.Errorf("Failed to build outputs on test: %s. Want:\n %#v\n Got\n %#v", test.Description, test.Expected, result) } } } @@ -532,7 +532,7 @@ func TestZencoderBuildOutput(t *testing.T) { "fixed_keyframe_interval": true, "constant_bitrate": true, "deinterlace": "on", - "base_url": "http://a:b@nyt-elastictranscoder-tests.s3.amazonaws.com/t/abcdef/", + "base_url": "http://a:b@nyt-elastictranscoder-tests.s3.amazonaws.com/t/abcdef", "filename": "test.mp4", }, }, @@ -567,7 +567,7 @@ func TestZencoderBuildOutput(t *testing.T) { "audio_bitrate": float64(128), "keyframe_interval": float64(90), "deinterlace": "on", - "base_url": "http://a:b@nyt-elastictranscoder-tests.s3.amazonaws.com/t/abcdef/", + "base_url": "http://a:b@nyt-elastictranscoder-tests.s3.amazonaws.com/t/abcdef/hls/hls_1080p", "filename": "test.m3u8", "type": "segmented", "hls_optimized_ts": true, @@ -604,7 +604,7 @@ func TestZencoderBuildOutput(t *testing.T) { "audio_bitrate": float64(128), "keyframe_interval": float64(90), "deinterlace": "on", - "base_url": "http://a:b@nyt-elastictranscoder-tests.s3.amazonaws.com/t/abcdef/", + "base_url": "http://a:b@nyt-elastictranscoder-tests.s3.amazonaws.com/t/abcdef", "filename": "test.webm", }, }, @@ -639,7 +639,7 @@ func TestZencoderBuildOutput(t *testing.T) { "audio_bitrate": float64(128), "keyframe_interval": float64(90), "deinterlace": "on", - "base_url": "http://user:pass%21word@nyt-elastictranscoder-tests.s3.amazonaws.com/t/abcdef/", + "base_url": "http://user:pass%21word@nyt-elastictranscoder-tests.s3.amazonaws.com/t/abcdef", "filename": "test.webm", }, },