Skip to content

Commit

Permalink
feat: support seek flag
Browse files Browse the repository at this point in the history
  • Loading branch information
ForeverSc committed Sep 23, 2024
1 parent caa7422 commit 71a49dc
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 29 deletions.
11 changes: 6 additions & 5 deletions lib/web-demuxer/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,13 @@ function getMediaInfo(file) {
}
}

function getAVPacket(file, time, type, streamIndex) {
function getAVPacket(file, time, type = 0, streamIndex = -1, seekFlag = 1) {
const workerFile = new WorkerFile(file);

workerFile.mount();

try {
const avPacket = Module.get_av_packet(workerFile.filePath, time, type, streamIndex);
const avPacket = Module.get_av_packet(workerFile.filePath, time, type, streamIndex, seekFlag);

return avPacketToObject(avPacket);
} catch(e) {
Expand All @@ -162,13 +162,13 @@ function getAVPacket(file, time, type, streamIndex) {
}
}

function getAVPackets(file, time) {
function getAVPackets(file, time, seekFlag = 1) {
const workerFile = new WorkerFile(file);

workerFile.mount();

try {
const avPacketList = Module.get_av_packets(workerFile.filePath, time);
const avPacketList = Module.get_av_packets(workerFile.filePath, time, seekFlag);
const result = [];

for (let i = 0; i < avPacketList.packets.size(); i++) {
Expand All @@ -192,13 +192,14 @@ async function readAVPacket(
end = 0,
type = 0,
streamIndex = -1,
seekFlag = 1
) {
const workerFile = new WorkerFile(file);

workerFile.mount();

try {
const result = await Module.read_av_packet(workerFile.filePath, start, end, type, streamIndex, {
const result = await Module.read_av_packet(workerFile.filePath, start, end, type, streamIndex, seekFlag, {
sendAVPacket: genSendAVPacket(msgId),
});

Expand Down
14 changes: 6 additions & 8 deletions lib/web-demuxer/web_demuxer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,7 @@ WebMediaInfo get_media_info(std::string filename) {
return media_info;
}


// TODO: support seek type
WebAVPacket get_av_packet(std::string filename, double timestamp, int type, int wanted_stream_nb)
WebAVPacket get_av_packet(std::string filename, double timestamp, int type, int wanted_stream_nb, int seek_flag)
{
AVFormatContext *fmt_ctx = NULL;
int ret;
Expand Down Expand Up @@ -388,7 +386,7 @@ WebAVPacket get_av_packet(std::string filename, double timestamp, int type, int
int64_t int64_timestamp = (int64_t)(timestamp * AV_TIME_BASE);
int64_t seek_time_stamp = av_rescale_q(int64_timestamp, AV_TIME_BASE_Q, fmt_ctx->streams[stream_index]->time_base);

if ((ret = av_seek_frame(fmt_ctx, stream_index, seek_time_stamp, AVSEEK_FLAG_BACKWARD)) < 0)
if ((ret = av_seek_frame(fmt_ctx, stream_index, seek_time_stamp, seek_flag)) < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot seek to the specified timestamp\n");
avformat_close_input(&fmt_ctx);
Expand Down Expand Up @@ -424,7 +422,7 @@ WebAVPacket get_av_packet(std::string filename, double timestamp, int type, int
return web_packet;
}

WebAVPacketList get_av_packets(std::string filename, double timestamp)
WebAVPacketList get_av_packets(std::string filename, double timestamp, int seek_flag)
{
AVFormatContext *fmt_ctx = NULL;
int ret;
Expand Down Expand Up @@ -465,7 +463,7 @@ WebAVPacketList get_av_packets(std::string filename, double timestamp)
int64_t int64_timestamp = (int64_t)(timestamp * AV_TIME_BASE);
int64_t seek_time_stamp = av_rescale_q(int64_timestamp, AV_TIME_BASE_Q, fmt_ctx->streams[stream_index]->time_base);

if ((ret = av_seek_frame(fmt_ctx, stream_index, seek_time_stamp, AVSEEK_FLAG_BACKWARD)) < 0)
if ((ret = av_seek_frame(fmt_ctx, stream_index, seek_time_stamp, seek_flag)) < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot seek to the specified timestamp\n");
throw std::runtime_error("Cannot seek to the specified timestamp");
Expand Down Expand Up @@ -496,7 +494,7 @@ WebAVPacketList get_av_packets(std::string filename, double timestamp)
return web_packet_list;
}

int read_av_packet(std::string filename, double start, double end, int type, int wanted_stream_nb, val js_caller)
int read_av_packet(std::string filename, double start, double end, int type, int wanted_stream_nb, int seek_flag, val js_caller)
{
AVFormatContext *fmt_ctx = NULL;
int ret;
Expand Down Expand Up @@ -539,7 +537,7 @@ int read_av_packet(std::string filename, double start, double end, int type, int
int64_t start_timestamp = (int64_t)(start * AV_TIME_BASE);
int64_t rescaled_start_time_stamp = av_rescale_q(start_timestamp, AV_TIME_BASE_Q, fmt_ctx->streams[stream_index]->time_base);

if ((ret = av_seek_frame(fmt_ctx, stream_index, rescaled_start_time_stamp, AVSEEK_FLAG_BACKWARD)) < 0)
if ((ret = av_seek_frame(fmt_ctx, stream_index, rescaled_start_time_stamp, seek_flag)) < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot seek to the specified timestamp\n");
avformat_close_input(&fmt_ctx);
Expand Down
11 changes: 6 additions & 5 deletions src/ffmpeg.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ function handleGetMediaInfo(data: GetMediaInfoMessageData, msgId: number) {
}

function handleGetAVPacket(data: GetAVPacketMessageData, msgId: number) {
const { file, time, streamType, streamIndex } = data;
const result = Module.getAVPacket(file, time, streamType, streamIndex);
const { file, time, streamType, streamIndex, seekFlag } = data;
const result = Module.getAVPacket(file, time, streamType, streamIndex, seekFlag);

self.postMessage(
{
Expand All @@ -102,8 +102,8 @@ function handleGetAVPacket(data: GetAVPacketMessageData, msgId: number) {
}

function handleGetAVPackets(data: GetAVPacketsMessageData, msgId: number) {
const { file, time } = data;
const result = Module.getAVPackets(file, time);
const { file, time, seekFlag } = data;
const result = Module.getAVPackets(file, time, seekFlag);

self.postMessage(
{
Expand All @@ -116,14 +116,15 @@ function handleGetAVPackets(data: GetAVPacketsMessageData, msgId: number) {
}

async function handleReadAVPacket(data: ReadAVPacketMessageData, msgId: number) {
const { file, start, end, streamType, streamIndex } = data;
const { file, start, end, streamType, streamIndex, seekFlag } = data;
const result = await Module.readAVPacket(
msgId,
file,
start,
end,
streamType,
streamIndex,
seekFlag
);

self.postMessage({
Expand Down
19 changes: 19 additions & 0 deletions src/types/avutil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,22 @@ export enum AVLogLevel {
*/
AV_LOG_TRACE = 56,
}

export enum AVSeekFlag {
/**
* seek backward
*/
AVSEEK_FLAG_BACKWARD = 1,
/**
* seeking based on position in bytes
*/
AVSEEK_FLAG_BYTE = 2,
/**
* seek to any frame, even non-keyframes
*/
AVSEEK_FLAG_ANY = 4,
/**
* seeking based on frame number
*/
AVSEEK_FLAG_FRAME = 8
}
5 changes: 4 additions & 1 deletion src/types/ffmpeg-worker-message.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AVLogLevel, AVMediaType } from "./avutil";
import { AVLogLevel, AVMediaType, AVSeekFlag } from "./avutil";

export enum FFMpegWorkerMessageType {
FFmpegWorkerLoaded = "FFmpegWorkerLoaded",
Expand Down Expand Up @@ -41,11 +41,13 @@ export interface GetAVPacketMessageData {
time: number;
streamType: AVMediaType;
streamIndex: number;
seekFlag: AVSeekFlag;
}

export interface GetAVPacketsMessageData {
file: File;
time: number;
seekFlag: AVSeekFlag;
}

export interface ReadAVPacketMessageData {
Expand All @@ -54,6 +56,7 @@ export interface ReadAVPacketMessageData {
end: number;
streamType: AVMediaType;
streamIndex: number;
seekFlag: AVSeekFlag;
}

export interface LoadWASMMessageData {
Expand Down
40 changes: 30 additions & 10 deletions src/web-demuxer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
AVLogLevel,
AVMediaType,
AVSeekFlag,
FFMpegWorkerMessageData,
FFMpegWorkerMessageType,
WebAVPacket,
Expand Down Expand Up @@ -157,32 +158,38 @@ export class WebDemuxer {
* @param time time in seconds
* @param streamType The type of media stream
* @param streamIndex The index of the media stream
* @param seekFlag The seek flag
* @returns WebAVPacket
*/
public getAVPacket(
time: number,
streamType = AVMediaType.AVMEDIA_TYPE_VIDEO,
streamIndex = -1,
seekFlag = AVSeekFlag.AVSEEK_FLAG_BACKWARD
): Promise<WebAVPacket> {
return this.getFromWorker(FFMpegWorkerMessageType.GetAVPacket, {
file: this.file!,
time,
streamType,
streamIndex,
seekFlag
});
}

/**
* Get all packets at a time point from all streams
* @param time time in seconds
* @param seekFlag The seek flag
* @returns WebAVPacket[]
*/
public getAVPackets(
time: number,
seekFlag = AVSeekFlag.AVSEEK_FLAG_BACKWARD
): Promise<WebAVPacket[]> {
return this.getFromWorker(FFMpegWorkerMessageType.GetAVPackets, {
file: this.file!,
time,
seekFlag
});
}

Expand All @@ -192,13 +199,15 @@ export class WebDemuxer {
* @param end end time in seconds
* @param streamType The type of media stream
* @param streamIndex The index of the media stream
* @param seekFlag The seek flag
* @returns ReadableStream<WebAVPacket>
*/
public readAVPacket(
start = 0,
end = 0,
streamType = AVMediaType.AVMEDIA_TYPE_VIDEO,
streamIndex = -1,
seekFlag = AVSeekFlag.AVSEEK_FLAG_BACKWARD
): ReadableStream<WebAVPacket> {
const queueingStrategy = new CountQueuingStrategy({ highWaterMark: 1 });
const msgId = this.msgId;
Expand Down Expand Up @@ -245,6 +254,7 @@ export class WebDemuxer {
end,
streamType,
streamIndex,
seekFlag
});
},
pull: () => {
Expand Down Expand Up @@ -297,46 +307,54 @@ export class WebDemuxer {
/**
* Seek video packet at a time point
* @param time seek time in seconds
* @param seekFlag The seek flag
* @returns WebAVPacket
*/
public seekVideoPacket(time: number) {
return this.getAVPacket(time, AVMediaType.AVMEDIA_TYPE_VIDEO);
public seekVideoPacket(time: number, seekFlag?: AVSeekFlag) {
return this.getAVPacket(time, AVMediaType.AVMEDIA_TYPE_VIDEO, undefined, seekFlag);
}

/**
* Seek audio packet at a time point
* @param time seek time in seconds
* @param seekFlag The seek flag
* @returns WebAVPacket
*/
public seekAudioPacket(time: number) {
return this.getAVPacket(time, AVMediaType.AVMEDIA_TYPE_AUDIO);
public seekAudioPacket(time: number, seekFlag?: AVSeekFlag) {
return this.getAVPacket(time, AVMediaType.AVMEDIA_TYPE_AUDIO, undefined, seekFlag);
}

/**
* Read video packet as a stream
* @param start start time in seconds
* @param end end time in seconds
* @param seekFlag The seek flag
* @returns ReadableStream<WebAVPacket>
*/
public readVideoPacket(start?: number, end?: number) {
public readVideoPacket(start?: number, end?: number, seekFlag?: AVSeekFlag) {
return this.readAVPacket(
start,
end,
AVMediaType.AVMEDIA_TYPE_VIDEO,
undefined,
seekFlag,
);
}

/**
* Read audio packet as a stream
* @param start start time in seconds
* @param end end time in seconds
* @param seekFlag The seek flag
* @returns ReadableStream<WebAVPacket>
*/
public readAudioPacket(start?: number, end?: number) {
public readAudioPacket(start?: number, end?: number, seekFlag?: AVSeekFlag) {
return this.readAVPacket(
start,
end,
AVMediaType.AVMEDIA_TYPE_AUDIO,
undefined,
seekFlag
);
}

Expand Down Expand Up @@ -417,10 +435,11 @@ export class WebDemuxer {
/**
* Seek and return EncodedVideoChunk
* @param time time in seconds
* @param seekFlag The seek flag
* @returns EncodedVideoChunk
*/
public async seekEncodedVideoChunk(time: number) {
const videoPacket = await this.seekVideoPacket(time);
public async seekEncodedVideoChunk(time: number, seekFlag?: AVSeekFlag) {
const videoPacket = await this.seekVideoPacket(time, seekFlag);

return this.genEncodedVideoChunk(videoPacket);
}
Expand All @@ -438,10 +457,11 @@ export class WebDemuxer {
/**
* Seek and return EncodedAudioChunk
* @param time time in seconds
* @param seekFlag The seek flag
* @returns EncodedAudioChunk
*/
public async seekEncodedAudioChunk(time: number) {
const audioPacket = await this.seekAudioPacket(time);
public async seekEncodedAudioChunk(time: number, seekFlag?: AVSeekFlag) {
const audioPacket = await this.seekAudioPacket(time, seekFlag);

return this.genEncodedAudioChunk(audioPacket);
}
Expand Down

0 comments on commit 71a49dc

Please sign in to comment.