Commit 42a3c80a authored by NzSN's avatar NzSN

Add encoder.cc for profile purposes.

parent fb85fc7d
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include "wasm.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/avutil.h>
}
#include <chrono>
#include <ctime>
///////////////////////////////////////////////////////////////////////////////
// Encoding Part //
///////////////////////////////////////////////////////////////////////////////
static int width_ = 0;
static int height_ = 0;
static int framerate_ = 0;
static int timescale = 90000;
static AVFrame *rgbaFrame;
static unsigned frameIndex = 0;
static AVFrame *frame;
static AVPacket *packet;
static AVCodecContext *cc;
static struct SwsContext* swsCtx = NULL;
static AVPacket *lastPkt = NULL;
EM_PORT_API(int) getPackets(uint8_t *buffer, uint32_t size, uint32_t *osize);
EM_PORT_API(uint8_t) encodeInit(int width, int height, int fps) {
int ret = 0;
width_ = width;
height_ = height;
framerate_ = fps;
const AVCodec *encoder = avcodec_find_encoder_by_name("libx264");
if (encoder == NULL) {
fprintf(stderr, "Unable to find H.264 decoder\n");
return 1;
}
cc = avcodec_alloc_context3(encoder);
if (cc == NULL) {
fprintf(stderr, "Unable to alloc codec context\n");
return 2;
}
// Setup encode parameters
cc->width = width;
cc->height = height;
cc->pix_fmt = AV_PIX_FMT_YUV420P;
cc->time_base = (AVRational){1, timescale};
cc->gop_size = 0;
if ((ret = avcodec_open2(cc, encoder, NULL) < 0)) {
fprintf(stderr, "Unable to open codec context: %s\n",
av_err2str(ret));
return 3;
}
packet = av_packet_alloc();
if (packet == NULL) {
fprintf(stderr, "Could not allocate packet\n");
}
frame = av_frame_alloc();
frame->format = cc->pix_fmt;
frame->width = cc->width;
frame->height = cc->height;
ret = av_frame_get_buffer(frame, 0);
if (ret < 0) {
fprintf(stderr, "Could not allocate the video frame data\n");
return 4;
}
swsCtx = sws_getCachedContext(swsCtx, width, height, AV_PIX_FMT_RGBA,
width, height, AV_PIX_FMT_YUV420P,
SWS_BICUBIC,
NULL, NULL, NULL);
return 0;
}
static std::chrono::duration<double> total;
/* Ret Values:
* 0: Success
* 1: AGAIN
* 2: Buffer too small
* 3: ERROR */
EM_PORT_API(int) encode(uint8_t *data, uint8_t *buffer, uint32_t size, uint32_t *osize) {
int ret = 0;
if (av_frame_make_writable(frame) < 0) {
fprintf(stderr, "Fail to make frame writable\n");
}
rgbaFrame = av_frame_alloc();
rgbaFrame->format =AV_PIX_FMT_RGBA;
rgbaFrame->height = cc->height;
rgbaFrame->width = cc->width;
avpicture_fill((AVPicture*)rgbaFrame, data, AV_PIX_FMT_RGBA, width_, height_);
//转换的YUV数据存放在frame
int outSliceH = sws_scale(swsCtx, (const uint8_t* const*)rgbaFrame->data, rgbaFrame->linesize, 0, height_,
frame->data, frame->linesize);
if (outSliceH <= 0) {
printf("outSliceH <= 0 \n");
return 3;
}
frame->pts = timescale / framerate_ * frameIndex;
frame->pict_type = AV_PICTURE_TYPE_I;
++frameIndex;
auto start = std::chrono::system_clock::now();
// Encode
ret = avcodec_send_frame(cc, frame);
if (ret < 0) {
fprintf(stderr, "Fail to encoding\n");
}
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
total += elapsed_seconds;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
printf("elapsed time (wasm): %lf\nTotal elapsed (wasm): %lf\n",
elapsed_seconds.count(),
total.count());
return getPackets(buffer, size, osize);
}
/* Ret Values:
* 0: Success
* 1: AGAIN or EOF
* 2: Buffer too small
* 3: ERROR */
EM_PORT_API(int) getPackets(uint8_t *buffer, uint32_t size, uint32_t *osize) {
int ret = 0;
uint8_t *pos = buffer;
int remainSize = size;
*osize = 0;
if (lastPkt != NULL && lastPkt->size > remainSize) {
memcpy(pos, lastPkt->data, lastPkt->size);
pos += lastPkt->size;
remainSize -= lastPkt->size;
av_packet_unref(lastPkt);
lastPkt = NULL;
} else if (lastPkt != NULL) {
/* Buffer is too small to containe the packet */
return 2;
}
while (1) {
ret = avcodec_receive_packet(cc, packet);
if (ret < 0) {
ret = 1;
goto DONE;
}
// For video frame avcodec_receive_packet should return
// only once.
if (remainSize > packet->size) {
memcpy(pos, packet->data, packet->size);
pos += packet->size;
remainSize -= packet->size;
} else {
lastPkt = packet;
break;
}
av_packet_unref(packet);
}
DONE:
*osize = size - remainSize;
return ret;
}
EM_PORT_API(int) flushEncoder() {
if (avcodec_send_frame(cc, NULL) < 0) {
return 1;
}
return 0;
}
int main(void) {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment