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 class="video-js" 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.