Closed Bellarmine-Head closed 1 year ago
@Bellarmine-Head Good morning. Thanks for reporting the issue. The said AWS SDK for .NET API documentation is generated from the service model https://github.com/aws/aws-sdk-net/blob/ddb9b60e8b804f561ffb5415eb729ecc3ca2582a/generator/ServiceModels/mediaconvert/mediaconvert-2017-08-29.docs.json#L17C6-L17C12
Looks like as pointed by you, the same issue is present in Media Convert API reference at https://docs.aws.amazon.com/mediaconvert/latest/apireference/jobs-id.html#jobs-idget. I was able to reproduce your use case following below example (snippet taken from https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/MediaConvert/Scenarios/CreateJob): MediaConvertWrapper.cs
using System;
using Amazon.MediaConvert;
using Amazon.MediaConvert.Model;
namespace MediaConvertTest
{
public class MediaConvertWrapper
{
private readonly IAmazonMediaConvert _amazonMediaConvert;
/// <summary>
/// Constructor for the MediaConvert wrapper.
/// </summary>
/// <param name="amazonMediaConvert">The injected MediaConvert client.</param>
public MediaConvertWrapper(IAmazonMediaConvert amazonMediaConvert)
{
_amazonMediaConvert = amazonMediaConvert;
}
// snippet-start:[MediaConvert.dotnetv3.CreateJob]
/// <summary>
/// Create a job to convert a media file.
/// </summary>
/// <param name="mediaConvertRole">The Amazon Resource Name (ARN) of the media convert role, as specified here:
/// https://docs.aws.amazon.com/mediaconvert/latest/ug/creating-the-iam-role-in-mediaconvert-configured.html</param>
/// <param name="fileInput">The Amazon Simple Storage Service (Amazon S3) location of the input media file.</param>
/// <param name="fileOutput">The Amazon S3 location for the output media file.</param>
/// <returns>The ID of the new job.</returns>
public async Task<string> CreateJob(string mediaConvertRole, string fileInput,
string fileOutput)
{
CreateJobRequest createJobRequest = new CreateJobRequest
{
Role = mediaConvertRole
};
createJobRequest.UserMetadata.Add("Customer", "Amazon");
JobSettings jobSettings = new JobSettings
{
AdAvailOffset = 0,
TimecodeConfig = new TimecodeConfig
{
Source = TimecodeSource.EMBEDDED
}
};
createJobRequest.Settings = jobSettings;
#region OutputGroup
OutputGroup ofg = new OutputGroup
{
Name = "File Group",
OutputGroupSettings = new OutputGroupSettings
{
Type = OutputGroupType.FILE_GROUP_SETTINGS,
FileGroupSettings = new FileGroupSettings
{
Destination = fileOutput
}
}
};
Output output = new Output
{
NameModifier = "_1"
};
#region VideoDescription
VideoDescription vdes = new VideoDescription
{
ScalingBehavior = ScalingBehavior.DEFAULT,
TimecodeInsertion = VideoTimecodeInsertion.DISABLED,
AntiAlias = AntiAlias.ENABLED,
Sharpness = 50,
AfdSignaling = AfdSignaling.NONE,
DropFrameTimecode = DropFrameTimecode.ENABLED,
RespondToAfd = RespondToAfd.NONE,
ColorMetadata = ColorMetadata.INSERT,
CodecSettings = new VideoCodecSettings
{
Codec = VideoCodec.H_264
}
};
output.VideoDescription = vdes;
H264Settings h264 = new H264Settings
{
InterlaceMode = H264InterlaceMode.PROGRESSIVE,
NumberReferenceFrames = 3,
Syntax = H264Syntax.DEFAULT,
Softness = 0,
GopClosedCadence = 1,
GopSize = 90,
Slices = 1,
GopBReference = H264GopBReference.DISABLED,
SlowPal = H264SlowPal.DISABLED,
SpatialAdaptiveQuantization = H264SpatialAdaptiveQuantization.ENABLED,
TemporalAdaptiveQuantization = H264TemporalAdaptiveQuantization.ENABLED,
FlickerAdaptiveQuantization = H264FlickerAdaptiveQuantization.DISABLED,
EntropyEncoding = H264EntropyEncoding.CABAC,
Bitrate = 5000000,
FramerateControl = H264FramerateControl.SPECIFIED,
RateControlMode = H264RateControlMode.CBR,
CodecProfile = H264CodecProfile.MAIN,
Telecine = H264Telecine.NONE,
MinIInterval = 0,
AdaptiveQuantization = H264AdaptiveQuantization.HIGH,
CodecLevel = H264CodecLevel.AUTO,
FieldEncoding = H264FieldEncoding.PAFF,
SceneChangeDetect = H264SceneChangeDetect.ENABLED,
QualityTuningLevel = H264QualityTuningLevel.SINGLE_PASS,
FramerateConversionAlgorithm =
H264FramerateConversionAlgorithm.DUPLICATE_DROP,
UnregisteredSeiTimecode = H264UnregisteredSeiTimecode.DISABLED,
GopSizeUnits = H264GopSizeUnits.FRAMES,
ParControl = H264ParControl.SPECIFIED,
NumberBFramesBetweenReferenceFrames = 2,
RepeatPps = H264RepeatPps.DISABLED,
FramerateNumerator = 30,
FramerateDenominator = 1,
ParNumerator = 1,
ParDenominator = 1
};
output.VideoDescription.CodecSettings.H264Settings = h264;
#endregion VideoDescription
#region AudioDescription
AudioDescription ades = new AudioDescription
{
LanguageCodeControl = AudioLanguageCodeControl.FOLLOW_INPUT,
// This name matches one specified in the following Inputs.
AudioSourceName = "Audio Selector 1",
CodecSettings = new AudioCodecSettings
{
Codec = AudioCodec.AAC
}
};
AacSettings aac = new AacSettings
{
AudioDescriptionBroadcasterMix = AacAudioDescriptionBroadcasterMix.NORMAL,
RateControlMode = AacRateControlMode.CBR,
CodecProfile = AacCodecProfile.LC,
CodingMode = AacCodingMode.CODING_MODE_2_0,
RawFormat = AacRawFormat.NONE,
SampleRate = 48000,
Specification = AacSpecification.MPEG4,
Bitrate = 64000
};
ades.CodecSettings.AacSettings = aac;
output.AudioDescriptions.Add(ades);
#endregion AudioDescription
#region Mp4 Container
output.ContainerSettings = new ContainerSettings
{
Container = ContainerType.MP4
};
Mp4Settings mp4 = new Mp4Settings
{
CslgAtom = Mp4CslgAtom.INCLUDE,
FreeSpaceBox = Mp4FreeSpaceBox.EXCLUDE,
MoovPlacement = Mp4MoovPlacement.PROGRESSIVE_DOWNLOAD
};
output.ContainerSettings.Mp4Settings = mp4;
#endregion Mp4 Container
ofg.Outputs.Add(output);
createJobRequest.Settings.OutputGroups.Add(ofg);
#endregion OutputGroup
#region Input
Input input = new Input
{
FilterEnable = InputFilterEnable.AUTO,
PsiControl = InputPsiControl.USE_PSI,
FilterStrength = 0,
DeblockFilter = InputDeblockFilter.DISABLED,
DenoiseFilter = InputDenoiseFilter.DISABLED,
TimecodeSource = InputTimecodeSource.EMBEDDED,
FileInput = fileInput
};
AudioSelector audsel = new AudioSelector
{
Offset = 0,
DefaultSelection = AudioDefaultSelection.NOT_DEFAULT,
ProgramSelection = 1,
SelectorType = AudioSelectorType.TRACK
};
audsel.Tracks.Add(1);
input.AudioSelectors.Add("Audio Selector 1", audsel);
input.VideoSelector = new VideoSelector
{
ColorSpace = ColorSpace.FOLLOW
};
createJobRequest.Settings.Inputs.Add(input);
#endregion Input
var jobId = "";
try
{
CreateJobResponse createJobResponse =
await _amazonMediaConvert.CreateJobAsync(createJobRequest);
jobId = createJobResponse.Job.Id;
}
catch (BadRequestException bre)
{
// If the endpoint was bad.
if (bre.Message.StartsWith("You must use the customer-"))
{
// The exception contains the correct endpoint; extract it.
var mediaConvertEndpoint = bre.Message.Split('\'')[1];
Console.WriteLine(
$"Request failed, please use endpoint {mediaConvertEndpoint}.");
}
else
throw;
}
return jobId;
}
// snippet-end:[MediaConvert.dotnetv3.CreateJob]
// snippet-start:[MediaConvert.dotnetv3.ListJobs]
/// <summary>
/// List all of the jobs with a particular status using a paginator.
/// </summary>
/// <param name="status">The status to use when listing jobs.</param>
/// <returns>The list of jobs matching the status.</returns>
public async Task<List<Job>> ListAllJobsByStatus(JobStatus? status = null)
{
var returnedJobs = new List<Job>();
var paginatedJobs = _amazonMediaConvert.Paginators.ListJobs(
new ListJobsRequest
{
Status = status
});
// Get the entire list using the paginator.
await foreach (var job in paginatedJobs.Jobs)
{
returnedJobs.Add(job);
}
return returnedJobs;
}
// snippet-end:[MediaConvert.dotnetv3.ListJobs]
// snippet-start:[MediaConvert.dotnetv3.GetJob]
/// <summary>
/// Get the job information for a job by its ID.
/// </summary>
/// <param name="jobId">The ID of the job.</param>
/// <returns>The Job object.</returns>
public async Task<Job> GetJobById(string jobId)
{
var jobResponse = await _amazonMediaConvert.GetJobAsync(
new GetJobRequest
{
Id = jobId
});
return jobResponse.Job;
}
// snippet-end:[MediaConvert.dotnetv3.GetJob]
}
}
Program.cs
using Amazon.MediaConvert;
using Amazon.MediaConvert.Model;
using MediaConvertTest;
string fileInput = "s3://some-bucket/some-file.mov";
string fileOutput = "s3://some-bucket/some-file_converted.mp4";
string mediaConvertRole = "arn:aws:iam::<<account-id>>:role/testmediaconvertrole";
Console.WriteLine("Welcome to the MediaConvert Create Job example.");
Console.WriteLine("Getting customer-specific MediaConvert endpoint.");
AmazonMediaConvertClient client = new AmazonMediaConvertClient();
DescribeEndpointsRequest describeRequest = new DescribeEndpointsRequest();
DescribeEndpointsResponse describeResponse = await client.DescribeEndpointsAsync(describeRequest);
string mediaConvertEndpoint = describeResponse.Endpoints[0].Url;
Console.WriteLine(new string('-', 80));
Console.WriteLine($"Using endpoint {mediaConvertEndpoint}.");
Console.WriteLine(new string('-', 80));
// Because you have a service URL for MediaConvert, you don't
// need to set RegionEndpoint. If you do, the ServiceURL will
// be overwritten.
AmazonMediaConvertConfig mcConfig = new AmazonMediaConvertConfig
{
ServiceURL = mediaConvertEndpoint,
};
AmazonMediaConvertClient mcClient = new AmazonMediaConvertClient(mcConfig);
var wrapper = new MediaConvertWrapper(mcClient);
Console.WriteLine(new string('-', 80));
Console.WriteLine($"Creating job for input file {fileInput}.");
var jobId = await wrapper.CreateJob(mediaConvertRole!, fileInput!, fileOutput!);
Console.WriteLine($"Created job with Job ID: {jobId}");
Console.WriteLine(new string('-', 80));
// snippet-end:[MediaConvert.dotnetv3.CreateJobSetup]
// snippet-start:[MediaConvert.dotnetv3.GetJobSetup]
Console.WriteLine(new string('-', 80));
Console.WriteLine($"Getting job information for Job ID {jobId}");
var job = await wrapper.GetJobById(jobId);
Console.WriteLine($"Job {job.Id} created on {job.CreatedAt:d} has status {job.Status}.");
Console.WriteLine(new string('-', 80));
// snippet-end:[MediaConvert.dotnetv3.GetJobSetup]
// snippet-start:[MediaConvert.dotnetv3.ListJobsSetup]
Console.WriteLine(new string('-', 80));
Console.WriteLine($"Listing all complete jobs.");
var completeJobs = await wrapper.ListAllJobsByStatus(JobStatus.COMPLETE);
completeJobs.ForEach(j =>
{
Console.WriteLine($"Job {j.Id} created on {j.CreatedAt:d} has status {j.Status}.");
});
// snippet-end:[MediaConvert.dotnetv3.ListJobsSetup]
Console.WriteLine(new string('-', 80));
Console.WriteLine("MediaConvert Create Job example complete.");
Console.WriteLine(new string('-', 80));
Welcome to the MediaConvert Create Job example.
Getting customer-specific MediaConvert endpoint.
--------------------------------------------------------------------------------
Using endpoint https://<<some-id>>.mediaconvert.us-east-2.amazonaws.com.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Creating job for input file s3://some-bucket/some-file.mov.
Created job with Job ID: 1691087883440-u4o7yv
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Getting job information for Job ID 1691087883440-u4o7yv
Job 1691087883440-u4o7yv created on 8/3/2023 has status PROGRESSING.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Listing all complete jobs.
--------------------------------------------------------------------------------
MediaConvert Create Job example complete.
--------------------------------------------------------------------------------
I will open an issue with MediaConvert service team for review.
Thanks, Ashish
P95945073
@Bellarmine-Head This appears to have been fixed at the following places:
This issue is now closed.
Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.
Describe the issue
The C#
Amazon.MediaConvert.AmazonMediaConvertClient.GetJobAsync
method says in its comments:-I would like to emphasize the word "completed" here.
I was worried about this, because I wanted to call
GetJobAsync
every 2 or 3 seconds to get an updated status... but the summary suggests that the method will only work for completed jobs.I tried it anyway, and got "PROGRESSING" a few times before I got "COMPLETED".
So method works for completed and also ongoing transcoding jobs! Perhaps the documentation could be updated to reflect that.
Links
Can't find a link to a .NET page, but here's one that's very similar and illustrates the problem....
https://docs.aws.amazon.com/mediaconvert/latest/apireference/jobs-id.html#jobs-idget