I am trying to view video in a browser using ffmpeg's decoder.
So, I made the decoder into a js file using emscripten.
By the way, the decoder seems to work, but only the last scene is displayed.
How can a video come out from start to finish?
Here is my code
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <libavcodec/avcodec.h> #include <SDL2/SDL.h> #define INBUF_SIZE 128 static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt, const char *filename, SDL_Window * screen, SDL_Renderer * renderer, SDL_Texture * texture) { char buf[1024]; int ret; ret = avcodec_send_packet(dec_ctx, pkt); if (ret < 0) { fprintf(stderr, "Error sending a packet for decoding\n"); exit(1); } while (ret >= 0) { ret = avcodec_receive_frame(dec_ctx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return; else if (ret < 0) { fprintf(stderr, "Error during decoding\n"); exit(1); } printf("saving frame %3d\n", dec_ctx->frame_number); fflush(stdout); SDL_Rect rect; rect.x = 0; rect.y = 0; rect.w = dec_ctx->width; rect.h = dec_ctx->height; SDL_UpdateYUVTexture( texture, // the texture to update &rect, // a pointer to the rectangle of pixels to update, or NULL to update the entire texture frame->data[0], // the raw pixel data for the Y plane frame->linesize[0], // the number of bytes between rows of pixel data for the Y plane frame->data[1], // the raw pixel data for the U plane frame->linesize[1], // the number of bytes between rows of pixel data for the U plane frame->data[2], // the raw pixel data for the V plane frame->linesize[2] // the number of bytes between rows of pixel data for the V plane ); SDL_RenderClear(renderer); SDL_RenderCopy( renderer, // the rendering context texture, // the source texture NULL, // the source SDL_Rect structure or NULL for the entire texture NULL // the destination SDL_Rect structure or NULL for the entire rendering // target; the texture will be stretched to fill the given rectangle ); SDL_RenderPresent(renderer); SDL_UpdateWindowSurface(screen); } } int main(int argc, char **argv) { const char *filename, *outfilename; const AVCodec *codec; AVCodecParserContext *parser; AVCodecContext *c= NULL; FILE *f; AVFrame *frame; uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; uint8_t *data; size_t data_size; int ret; AVPacket *pkt; if (argc <= 2) { fprintf(stderr, "Usage: %s <input file> <output file>\n" "And check your input file is encoded by mpeg1video please.\n", argv[0]); exit(0); } filename = argv[1]; outfilename = argv[2]; pkt = av_packet_alloc(); if (!pkt) exit(1); /* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */ memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE); ret = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER); // [1] if (ret != 0) { // error while initializing SDL printf("Could not initialize SDL - %s\n.", SDL_GetError()); // exit with error // return -1; } /* find the MPEG-1 video decoder */ codec = avcodec_find_decoder(AV_CODEC_ID_H265); if (!codec) { fprintf(stderr, "Codec not found\n"); exit(1); } parser = av_parser_init(codec->id); if (!parser) { fprintf(stderr, "parser not found\n"); exit(1); } c = avcodec_alloc_context3(codec); if (!c) { fprintf(stderr, "Could not allocate video codec context\n"); exit(1); } /* open it */ if (avcodec_open2(c, codec, NULL) < 0) { fprintf(stderr, "Could not open codec\n"); exit(1); } f = fopen(filename, "rb"); if (!f) { fprintf(stderr, "Could not open %s\n", filename); exit(1); } frame = av_frame_alloc(); if (!frame) { fprintf(stderr, "Could not allocate video frame\n"); exit(1); } // Create a window with the specified position, dimensions, and flags. SDL_Window * screen = SDL_CreateWindow( // [2] "SDL Video Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 360, SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI ); if (!screen) { // could not set video mode printf("SDL: could not set video mode - exiting.\n"); // exit with Error // return -1; } // // // SDL_GL_SetSwapInterval(1); // A structure that contains a rendering state. SDL_Renderer * renderer = NULL; // Use this function to create a 2D rendering context for a window. renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED); // [3] // A structure that contains an efficient, driver-specific representation // of pixel data. SDL_Texture * texture = NULL; // Use this function to create a texture for a rendering context. texture = SDL_CreateTexture( // [4] renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, 640, 360 ); while (!feof(f)) { /* read raw data from the input file */ data_size = fread(inbuf, 1, INBUF_SIZE, f); if (!data_size) break; /* use the parser to split the data into frames */ data = inbuf; while (data_size > 0) { ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size, data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); if (ret < 0) { fprintf(stderr, "Error while parsing\n"); exit(1); } data += ret; data_size -= ret; if (pkt->size) decode(c, frame, pkt, outfilename, screen, renderer, texture); } } /* flush the decoder */ decode(c, frame, NULL, outfilename, screen, renderer, texture); fclose(f); av_parser_close(parser); avcodec_free_context(&c); av_frame_free(&frame); av_packet_free(&pkt); return 0; } Is it possible to continuously play sdl in a browser?
https://stackoverflow.com/questions/66020171/how-can-i-display-the-video-on-sdl-converted-to-emscripten February 03, 2021 at 09:51AM
没有评论:
发表评论