Skip to content

Commit

Permalink
fix: fix metadata include rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
mengxiaoxuan committed Nov 27, 2022
1 parent 8d31943 commit 11d0843
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 24 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [0.1.3](https://github.com/wanwu/cheetah-capture/compare/v0.1.0...v0.1.3) (2022-11-27)


### Features

* change lib struct ([659766e](https://github.com/wanwu/cheetah-capture/commit/659766e6dcc183f31078cd39d5e1faea079b1a64))


### Bug Fixes

* del log ([100fa44](https://github.com/wanwu/cheetah-capture/commit/100fa44da4436384a4a09278f15e04d9a015d75e))
* fix metadata include rotation ([add084d](https://github.com/wanwu/cheetah-capture/commit/add084d89b2f6103a2277734c855a4d6f05e0968))
* improve exception handling ([3a214ea](https://github.com/wanwu/cheetah-capture/commit/3a214ea74a6c6f4887c66d1dda965a10f14f9de9))

### [0.1.2](https://github.com/wanwu/cheetah-capture/compare/v0.1.0...v0.1.2) (2022-11-23)


Expand Down
4 changes: 2 additions & 2 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
<!-- <script src="./capture.js" type="application/javascript"></script> -->
<script src="../dist/index.js" type="application/javascript"></script>
<script>
const workerPath = new URL('http://127.0.0.1:5501/dist/capture.worker.js');
const wasmPath = new URL('http://127.0.0.1:5501/dist/capture.worker.wasm');
const workerPath = new URL(location.origin + '/dist/capture.worker.js');
const wasmPath = new URL(location.origin + '/dist/capture.worker.wasm');
let button = document.querySelector('#js_button');
let resultContainer = document.querySelector('#js_result');
let fileInput = document.querySelector('#js_file');
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cheetah-capture",
"version": "0.1.2",
"version": "0.1.3",
"description": "cheetah-capture是基于ffmpeg的wasm截取视频帧工具",
"keywords": [
"ffmpeg",
Expand Down
27 changes: 23 additions & 4 deletions src/capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ AVFrame *initAVFrame(AVCodecContext *pCodecCtx, uint8_t **frameBuffer)

return pFrameRGB;
}


static char *dump_metadata(void *ctx, AVDictionary *m, const char *indent)
{
char *rotate = "0";
if (m && !(av_dict_count(m) == 1 && av_dict_get(m, "language", NULL, 0))) {
AVDictionaryEntry *tag = NULL;
av_log(ctx, AV_LOG_INFO, "%sMetadata:\n", indent);
while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
if (strcmp(tag->key, "rotate") == 0) {
rotate = tag->value;
return rotate;
}
}
}
return rotate;
}

int getIframes(AVFormatContext *qFormatCtx, int videoStream, int timeStamp, int *framesList, int idx)
{
// ===============寻找I帧
Expand Down Expand Up @@ -202,10 +220,6 @@ int videoStream, int time, FrameInfo *frameInfo, int *Iframe, int counts, int id
AVFrame *pFrameRGB = initAVFrame(pNewCodecCtx, &frameBuffer);

pFrameRGB = readAVFrame(pNewCodecCtx, pFormatCtx, pFrameRGB, videoStream, time, frameInfo, Iframe, counts);
// if (pFrameRGB == NULL) {
// fprintf(stderr, "readAVFrame failed\n");
// return NULL;
// }
ImageData *imageData = NULL;
imageData = (ImageData *)malloc(sizeof(ImageData));
imageData->width = (uint32_t)pNewCodecCtx->width;
Expand Down Expand Up @@ -302,6 +316,11 @@ ImageData **captureByCount(int count, char *path, int id)
// 初始化结构体
frameInfo->lastKeyframe = 0;
frameInfo->lastIframe = -1;
AVStream *st = pFormatCtx->streams[videoStream];
char *rotate = dump_metadata(NULL, st->metadata, " ");
static char buf[1024];
sprintf(buf, "setAngle(%s)", rotate);
emscripten_run_script(buf);
dataList[0] = *(getSpecificFrame(pNewCodecCtx, pFormatCtx, videoStream, 0, frameInfo, Iframe, 0, id));
// emscripten_run_script(get_js_code(dataList[0])); // 把第一帧传出去
// TODO:
Expand Down
6 changes: 6 additions & 0 deletions src/capture.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ class ImageCapture {
const imageCapture = new ImageCapture();

let isInit = false;
let angle = 0;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function transpostFrame(ptr, id) {
const data = imageCapture.getImageInfo(ptr / 4);
Expand All @@ -175,6 +176,7 @@ function transpostFrame(ptr, id) {
type: 'receiveImageOnchange',
...data,
id,
angle,
});
// console.log('transpostFrame==>', id, imageCapture.captureInfo);
if (imageCapture.imageList[id].length >= imageCapture.captureInfo[id]) {
Expand All @@ -186,7 +188,11 @@ function transpostFrame(ptr, id) {
});
}
}
function setAngle(a: string) {
angle = +a;
}
self.transpostFrame = transpostFrame;
self.setAngle = setAngle;
const initPromise: Promise<URL> = new Promise(res => {
(self as any).goOnInit = res;
});
Expand Down
81 changes: 66 additions & 15 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,26 +71,77 @@ const pool = createRequest();
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d')!;

async function getUrl(width: number, height: number, imageDataBuffer):
function rotateImage(imageData, direction = 'l') {
const H = imageData.height;
const W = imageData.width;
const imgDt1 = new ImageData(H, W);
const imgDt2 = new ImageData(H, W);
const dt0 = imageData.data;
const dt1 = imgDt1.data;
const dt2 = imgDt2.data;

// 2. Transposex
let r = 0;
let r1 = 0; // index of red pixel in old and new ImageData, respectively
for (let y = 0, lenH = H; y < lenH; y++) {
for (let x = 0, lenW = W; x < lenW; x++) {
r = (x + lenW * y) * 4;
r1 = (y + lenH * x) * 4;
dt1[r1 + 0] = dt0[r + 0];
dt1[r1 + 1] = dt0[r + 1];
dt1[r1 + 2] = dt0[r + 2];
dt1[r1 + 3] = dt0[r + 3];
}
}

// 3. Reverse width / height
for (let y = 0, lenH = W; y < lenH; y++) {
for (let x = 0, lenW = H; x < lenW; x++) {
r = (x + lenW * y) * 4;
r1 = direction === 'l'
? (x + lenW * (lenH - 1 - y)) * 4
: ((lenW - 1 - x) + lenW * y) * 4;
dt2[r1 + 0] = dt1[r + 0];
dt2[r1 + 1] = dt1[r + 1];
dt2[r1 + 2] = dt1[r + 2];
dt2[r1 + 3] = dt1[r + 3];
}
}
return imgDt2;
}
async function getUrl(width: number, height: number, imageDataBuffer, angle: number):
Promise<{url: string, blob?: Blob}> {
canvas.width = width;
canvas.height = height;
let canvasWith = width;
let canvasHeight = height;
const imageData = new ImageData(imageDataBuffer, width, height);
ctx.putImageData(imageData, 0, 0, 0, 0, width, height);
let imgData = null;
switch (angle / 90) {
case 1:
imgData = rotateImage(imageData, 'r');
canvasWith = height;
canvasHeight = width;
break;
case 2:
imgData = rotateImage(imageData, 'r');
imgData = rotateImage(imageData, 'r');
break;
case 3:
imgData = rotateImage(imageData, 'l');
canvasWith = height;
canvasHeight = width;
break;
default:
imgData = imageData;
break;
}
canvas.width = canvasWith;
canvas.height = canvasHeight;
ctx.putImageData(imgData, 0, 0, 0, 0, canvasWith, canvasHeight);
// const blob = new Blob([imageDataBuffer.buffer], {type: 'image/png'} /* (1) */);
return {
url: canvas.toDataURL('image/jpeg'),
// blob: blob,
};
// return new Promise(resolve => {
// canvas.toBlob(blob => {
// const url = URL.createObjectURL(blob);
// resolve({
// url,
// blob,
// });
// });
// });
}

function startCapture(id: number, info: CaptureInfo['info'], path: CaptureInfo['path'], file: CaptureInfo['file']) {
Expand Down Expand Up @@ -118,8 +169,8 @@ export async function initCapture({
worker.addEventListener('message', async e => {
switch (e?.data?.type) {
case Events.receiveImageOnchange: {
const {imageDataBuffer, width, height, duration, id} = e.data || {};
const img = await getUrl(width, height, imageDataBuffer);
const {imageDataBuffer, width, height, duration, id, angle} = e.data || {};
const img = await getUrl(width, height, imageDataBuffer, angle);
const cbk = pool.getCbk(id);
const {onChange} = cbk;
const info = {width, height, duration: duration / 1000000};
Expand Down

0 comments on commit 11d0843

Please sign in to comment.