Read the original article:Video Audio Playback
Video Audio Playback
Problem Description
Developers may encounter the following issues with the Video component in HarmonyOS:
- Video playback stuttering on real devices
- Seeking (jumping) to a specific time via dragging fails
- The
Videocomponent fails to load online videos - Unable to retrieve thumbnails from network videos
This article aims to provide solutions to these problems.
Background Knowledge
HarmonyOS Documentation:
-
setCurrentTime: Specifies the playback position of a video. -
request: Asynchronous HTTP request method that returns a result usingPromise. -
requestInStream: Initiates an HTTP request based on a URL and returns a streamed response. Asynchronous, also usingPromise.
Common Scenarios:
- Video stuttering during playback on a physical device
- Seeking fails: calling
this.controller.setCurrentTime(value)does not jump to the specified time, and may reset to the beginning - Video component fails to load online videos or retrieve thumbnails: videos work fine when loaded locally (e.g., from the file system), but fail when streamed online — result is a black screen.
Troubleshooting Process
Q: When downloading the video to the sandbox and getting the thumbnail, an error message appears: http request failed, code: 2300023, message: Failed to write the received data to disk/application.
A: The default value of the maximum byte limit of the response message for the http request is 510241024. If the video is too large, an error message will be reported. Set the maximum byte limit of the response data to 100M.
http.createHttp().request(url,
{
method: http.RequestMethod.GET,
connectTimeout: 60000,
readTimeout: 60000,
maxLimit: 100 * 1024 * 1024,
expectDataType: 2,
},
When the maximum limit of 100M is exceeded, use requestInStream to return in stream mode. There is no size limit, but you should also pay attention to the phone's memory. Or use request to complete the download function.
Implementation Steps
- Video playback stuttering: After adding the network permission ohos.permission.INTERNET in the
module.json5file of the project, it can play normally. The configuration content is as follows:
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
Code Snippet/ Configuration
- Failed to drag the video to jump to the specified time point: Set the precision mode to this.controller.setCurrentTime(10, SeekMode.Accurate), and if the current cached playback time of the Video component is lower than the jump position, there will be no response when jumping. The sample code is as follows:
@Component
@Entry
struct Index {
private controller: VideoController = new VideoController()
build() {
Column() {
Video({
src: 'https://cdn.xxxxxxx.com//h5_images/files/videos/xxxxxxxx.mp4',
// previewUri: this.previewUris,
controller: this.controller,
currentProgressRate: 1
})
.width('100%')
.height(300)
.autoPlay(true)
.objectFit(ImageFit.Contain)
.controls(true)
Button('xxx').onClick(() => {
this.controller.setCurrentTime(10, SeekMode.Accurate)
})
}
}
}
The Video component cannot load online videos or get thumbnails: You need to download online videos to your local computer through a request, and then play and get thumbnails.
The sample code is as follows:
import { http } from '@kit.NetworkKit'
import { BusinessError } from '@kit.BasicServicesKit';
import fs from '@ohos.file.fs';
import { promptAction } from '@kit.ArkUI';
import { media } from '@kit.MediaKit';
import { image } from '@kit.ImageKit';
@Entry
@Component
struct VideoTest {
@State videoPath: string = ''
@State pixelMap: image.PixelMap | undefined = undefined;
controller: VideoController = new VideoController();
build() {
Row() {
Column() {
Button('Download')
.width('50%')
.height(44)
.onClick(() => {
this.saveHttpVideo('https://file.xxxxxxx.net/ChildPlat/Album/20200617/Video/xxxxx.mp4')
})
Video({
src: this.videoPath,
previewUri: this.pixelMap,
controller: this.controller
})
.width('100%')
.height(600)
.autoPlay(true)
.controls(true)
.loop(false)
.objectFit(ImageFit.Contain)
}
.width('100%')
}
.height('100%')
}
// download
async saveHttpVideo(url: string) {
http.createHttp().request(url,
{
method: http.RequestMethod.GET,
connectTimeout: 60000,
readTimeout: 60000,
expectDataType: 2,
},
async (error: BusinessError, data: http.HttpResponse) => {
if (error) {
console.error(`http reqeust failed with. Code: ${error.code}, message: ${error.message}`);
} else {
if (http.ResponseCode.OK === data.responseCode) {
let buffer: ArrayBuffer = data.result as ArrayBuffer;
try {
const dateStr = (new Date().getTime()).toString()
let path = getContext().filesDir + '/' + dateStr + '.mp4'
let file = await fs.open(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
// write to file
await fs.write(file.fd, buffer);
// close file
await fs.close(file.fd);
promptAction.showToast({message:'Download completed'})
this.testFetchFrameByTime(path)
this.videoPath = 'file://' + path;
console.log("videoPath = " + path)
} catch (error) {
console.error("error is " + JSON.stringify(error))
}
} else {
console.error("error occurred when image downloaded!")
}
}
})
}
// Get the thumbnail
async testFetchFrameByTime(filePath: string) {
// Create an AVImageGenerator object
let avImageGenerator: media.AVImageGenerator = await media.createAVImageGenerator()
let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY);
let avFileDescriptor: media.AVFileDescriptor = { fd: file.fd };
avImageGenerator.fdSrc = avFileDescriptor;
// Initialize the input parameters
let timeUs = 0
let queryOption = media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC
let param: media.PixelMapParams = { width : 300, height : 400, }
// Get thumbnail (promise mode)
this.pixelMap = await avImageGenerator.fetchFrameByTime(timeUs, queryOption, param)
// Release resources (promise mode)
avImageGenerator.release()
fs.closeSync(file);
}
}
- When the video component plays online videos and autoplay is not set to true, the video will not be played by default and the video display will be black. How to make the video component display the online video thumbnail when it does not automatically play by default: you need to download the video to the local computer in aboutToAppear, get the thumbnail, and display the thumbnail through the previewUri parameter of the video component.
- The sample code is as follows:
import { http } from '@kit.NetworkKit'
import { BusinessError } from '@kit.BasicServicesKit';
import fs from '@ohos.file.fs';
import { media } from '@kit.MediaKit';
import { image } from '@kit.ImageKit';
@Entry
@Component
struct VideoTest {
@State videoPath: string = ''
@State pixelMap: image.PixelMap | undefined = undefined;
controller: VideoController = new VideoController();
aboutToAppear(): void {
this.saveHttpVideo('https://xxx.mp4')
}
build() {
Row() {
Column() {
Video({
src: this.videoPath,
previewUri: this.pixelMap,
controller: this.controller
})
.width('100%')
.height(600)
.controls(true)
.loop(false)
.objectFit(ImageFit.Contain)
}
.width('100%')
}
.height('100%')
}
// Download
async saveHttpVideo(url: string) {
http.createHttp().request(url,
{
method: http.RequestMethod.GET,
connectTimeout: 60000,
readTimeout: 60000,
expectDataType: 2,
},
async (error: BusinessError, data: http.HttpResponse) => {
if (error) {
console.error(`http reqeust failed with. Code: ${error.code}, message: ${error.message}`);
} else {
if (http.ResponseCode.OK === data.responseCode) {
let buffer: ArrayBuffer = data.result as ArrayBuffer;
try {
const dateStr = (new Date().getTime()).toString()
let path = getContext().filesDir + '/' + dateStr + '.mp4'
let file = await fs.open(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
// Write to file
await fs.write(file.fd, buffer);
// Close file
await fs.close(file.fd);
//promptAction.showToast({message:'Download completed'})
this.testFetchFrameByTime(path)
this.videoPath = 'file://' + path;
console.log("videoPath = " + path)
} catch (error) {
console.error("error is " + JSON.stringify(error))
}
} else {
console.error("error occurred when image downloaded!")
}
}
})
}
// Get thumbnail
async testFetchFrameByTime(filePath: string) {
// Create AVImageGenerator object
let avImageGenerator: media.AVImageGenerator = await media.createAVImageGenerator()
let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY);
let avFileDescriptor: media.AVFileDescriptor = { fd: file.fd };
avImageGenerator.fdSrc = avFileDescriptor;
// Initialize input parameters
let timeUs = 0
let queryOption = media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC
let param: media.PixelMapParams = { width : 300, height : 400, }
// Get thumbnail (promise mode)
this.pixelMap = await avImageGenerator.fetchFrameByTime(timeUs, queryOption, param)
// Release resources (promise mode)
avImageGenerator.release()
fs.closeSync(file);
}
}
Related Documents or Links
https://developer.huawei.com/consumer/en/doc/harmonyos-references/ts-media-components-video#events
Top comments (0)