Description:
I have an API (ASP.Net 5) which connect to an IP Camera through RTSP. The camera send a h264 stream converted with ffmpeg as m3u8 stream which is returned to the angular client as follow:
public async Task<ActionResult> GetCameraH264Stream()
{
string deviceIp = "rtsp://[CAMERA_IP]/";
string recordingUri = "rtsp://[USER:PASSWORD]@[CAMERA_IP]/axis-media/media.amp";
string output = Path.Combine(Path.GetTempPath(), Guid.NewGuid() ".m3u8");
var mediaInfo = await FFmpeg.GetMediaInfo(recordingUri);
var conversionResult = FFmpeg.Conversions.New()
.AddStream(mediaInfo.Streams)
.SetOutput(output)
.Start();
// Allow any Cors
Response.Headers.Add("Access-Control-Allow-Origin", "*");
Response.Headers.Add("Cache-Control", "no-cache");
// Open the file, and read the stream to return to the client
FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream");
result.EnableRangeProcessing = true;
return result;
}
If I call this methods directly, the browser download a file, which I can read with VLC.
In my Angular app, I have this component:
app-vjs-player
@Component({
selector: 'app-vjs-player',
template: '<video #target controls muted playsinline preload="none">
</video>',
encapsulation: ViewEncapsulation.None,
})
export class VjsPlayerComponent implements OnInit, OnDestroy {
@ViewChild('target', {static: true}) target: ElementRef;
@Input() options: {
fluid: boolean,
aspectRatio: string,
autoplay: boolean,
sources: {
src: string,
type: string,
}[],
vhs: {
overrideNative: true
},
};
player: videojs.Player;
constructor(
private elementRef: ElementRef,
) { }
ngOnInit() {
// instantiate Video.js
this.player = videojs(this.target.nativeElement, this.options, function onPlayerReady() {
console.log('onPlayerReady', this);
});
}
ngOnDestroy() {
// destroy player
if (this.player) {
this.player.dispose();
}
}
}
This component is used like this:
TS
playerOptions = {
fluid: false,
aspectRatio: "16:9",
autoplay: false,
sources: [{
src: 'https://localhost:44311/api/GetCameraH264Stream',
type: 'application/x-mpegURL',
}],
}
HTML
<app-vjs-player #videoJs [options]="playerOptions"></app-vjs-player>
Problem
All this seems to work pretty well, until vjs throw this error when the api return the stream :
ERROR: (CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED) The media could not be loaded, either because the server or network failed or because the format is not supported
When I open the network dev tools, the request status is "Canceled", but I don't know if videojs cancel it because the filestreal can't be read, or if it is because of the way the API return the stream.
Any idea ?
Source
Forwarding RTSP stream from IP Camera to Browser in ASP.NET Core
EDIT
- I tried to limit the resolution and the bitrate but I can't configure the camera like that, there is other application using it. The camera do not have any streaming url allowing this configuration
- I have been able to get an image from my code after changing the content type of the api response. I changed:
FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream");
to
FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/x-mpegURL");
With this the first packet is displayed, but the next requests are still canceled.
CodePudding user response:
The change on the response ContentType is working (see last edit on question).
It seems that the canceled request was due to the slow network. All the code above is working as is, except for the last modif ( application/octet-stream => application/x-mpegURL ). Here is the updated api method:
public async Task<ActionResult> GetCameraH264Stream()
{
string deviceIp = "rtsp://[CAMERA_IP]/";
string recordingUri = "rtsp://[USER:PASSWORD]@[CAMERA_IP]/axis-media/media.amp";
string output = Path.Combine(Path.GetTempPath(), Guid.NewGuid() ".m3u8");
var mediaInfo = await FFmpeg.GetMediaInfo(recordingUri);
var conversionResult = FFmpeg.Conversions.New()
.AddStream(mediaInfo.Streams)
.SetOutput(output)
.Start();
// Allow any Cors
Response.Headers.Add("Access-Control-Allow-Origin", "*");
Response.Headers.Add("Cache-Control", "no-cache");
// Open the file, and read the stream to return to the client
FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/x-mpegURL");
result.EnableRangeProcessing = true;
return result;
}