Диктофон

Мне интересна библиотека (для окон), написанная на Delphi/Pascal или С++, которая позволяет мне записывать (в формат видео) экран рабочего стола, требования:

  • должен иметь возможность указывать частоту кадров или, по крайней мере, записывать @5fps;
  • должен быть открытым или свободным;
  • формат вывода может быть практически любым, но качество должно быть достаточно хорошим, чтобы читать текст из записи;

плюсы, если возможно:

  • возможность записи без цветов (оттенки серого);
  • отображение нескольких дисплеев;
  • кросс-платформа (Windows и Linux, другие платформы тоже были бы хороши, но не обязательно);

Если случайно, я не объяснил что-то правильно, пожалуйста, не стесняйтесь спрашивать, чтобы я мог перефразировать или дать более подробную информацию и т.д.

Ответ 1

FFMPEG поддерживает захват экрана (кастинг) и является кросс-платформенным.

Ответ 2

Вы можете попробовать Windows Media Encoder (бесплатно, только wmv/asf) или VLC (GPL, Win/OSX/Linux). Имейте в виду, что "аппаратные ускоренные" представления (например, рендеринг Direct3D и OpenGL) не будут доступны, и некоторые потери качества будут ощущаться из-за сжатия видео. Сколько вы потеряете, будет зависеть от ваших настроек (кодек, битрейт, разрешение и т.д.)

Пример: Как потоковое использование вашего рабочего стола с помощью VLC

vlc screen:// :screen-fps=30 :screen-caching=100 --sout '#transcode{vcodec=mp4v,vb=4096,acodec=mpga,ab=256,scale=1,width=1280,height=800}:rtp{dst=192.168.1.2,port=1234,access=udp,mux=ts}'

В документации VLC вы можете найти дополнительные параметры, например, для сохранения потока в виде файла.

Ответ 3

Это тот, который я использую с Delphi, он называется "" Профессиональный компонент экранной камеры". По общему признанию, мне пришлось внести некоторые изменения для поддержки Unicode-версий (замените PChar на PAnsiChar, замените Char на AnsiChar).

Он будет с успехом записываться в любой фреймрере, который я ему установил, будет кодировать видео с любым кодеком, который я укажу (если хотите), и позволяет указать регион, который вы хотите записать.

Также идет демонстрационный проект!

О, и это бесплатный/открытый источник!

Ответ 4

FFmpeg может использоваться для захвата экрана.

смотреть видеозапись на экране с помощью FFMPEG: https://www.youtube.com/watch?v=a31bBY3HuxE

Формат контейнера: MP4

Кодек: MPEG4

Выполните шаги для записи экрана в видео с помощью FFmpeg и других библиотек.

  • Инициализировать требуемые регистры

  • использовать x11grab (для Linux-системы) в av_find_input_format

  • укажите позицию для захвата видео на экране (например.: 0.0 + 10, 250 "в av_format_open_input)

  • Теперь переходим к обычной инициализации видеопараметров и распределению памяти.

  • запустите захват кадров и сохраните их в файле.

  • Наконец, отпустите выделенные ресурсы после их завершения!

ниже код написан на С++ и использует формат видео в формате linux (ubuntu) в формате mp4.

// sample code to record the computer screen !

      #ifndef SCREENRECORDER_H
      #define SCREENRECORDER_H

      #include <iostream>
      #include <cstdio>
      #include <cstdlib>
      #include <fstream>
      #include <cstring>
      #include <math.h>
      #include <string.h>

      #define __STDC_CONSTANT_MACROS

      //FFMPEG LIBRARIES
      extern "C"
      {
      #include "libavcodec/avcodec.h"
      #include "libavcodec/avfft.h"

      #include "libavdevice/avdevice.h"

      #include "libavfilter/avfilter.h"
      #include "libavfilter/avfiltergraph.h"
      #include "libavfilter/buffersink.h"
      #include "libavfilter/buffersrc.h"

      #include "libavformat/avformat.h"
      #include "libavformat/avio.h"

      // libav resample

      #include "libavutil/opt.h"
      #include "libavutil/common.h"
      #include "libavutil/channel_layout.h"
      #include "libavutil/imgutils.h"
      #include "libavutil/mathematics.h"
      #include "libavutil/samplefmt.h"
      #include "libavutil/time.h"
      #include "libavutil/opt.h"
      #include "libavutil/pixdesc.h"
      #include "libavutil/file.h"

      // lib swresample

      #include "libswscale/swscale.h"

      }



      class ScreenRecorder
      {
      private:
        AVInputFormat *pAVInputFormat;
        AVOutputFormat *output_format;

        AVCodecContext *pAVCodecContext;

        AVFormatContext *pAVFormatContext;

        AVFrame *pAVFrame;
        AVFrame *outFrame;

        AVCodec *pAVCodec;
        AVCodec *outAVCodec;

        AVPacket *pAVPacket;

        AVDictionary *options;

        AVOutputFormat *outAVOutputFormat;
        AVFormatContext *outAVFormatContext;
        AVCodecContext *outAVCodecContext;

        AVStream *video_st;
        AVFrame *outAVFrame;

        const char *dev_name;
        const char *output_file;

        double video_pts;

        int out_size;
        int codec_id;
        int value;
        int VideoStreamIndx;

      public:

        ScreenRecorder();
        ~ScreenRecorder();

        int openCamera();
        int init_outputfile();
        int collectFrames();

      };

      #endif


      using namespace std;

      ScreenRecorder::ScreenRecorder()
      {
        cout<<"\n\n Registering required functions...";
        av_register_all();
        avcodec_register_all();
        avdevice_register_all();
        cout<<"\n\n Registered successfully...";
      }

      ScreenRecorder::~ScreenRecorder()
      {

        avformat_close_input(&pAVFormatContext);
        if( !pAVFormatContext )
        {
        cout<<"\n\n1.Success : avformat_close_input()";
        }
        else
        {
        cout<<"\n\nError : avformat_close_input()";
        }

        avformat_free_context(pAVFormatContext);
        if( !pAVFormatContext )
        {
        cout<<"\n\n2.Success : avformat_free_context()";
        }
        else
        {
        cout<<"\n\nError : avformat_free_context()";
        }

      cout<<"\n\n---------------Successfully released all resources------------------\n\n\n";
      cout<<endl;
      cout<<endl;
      cout<<endl;
      }

      int ScreenRecorder::collectFrames()
      {
        int flag;
        int frameFinished;
      //when you decode a single packet, you still don't have information enough to have a frame [depending on the type of codec, some of them //you do], when you decode a GROUP of packets that represents a frame, then you have a picture! that why frameFinished will let //you know you decoded enough to have a frame.

        int frame_index = 0;
        value = 0;

        pAVPacket = (AVPacket *)av_malloc(sizeof(AVPacket));
        av_init_packet(pAVPacket);

        pAVFrame = av_frame_alloc();
        if( !pAVFrame )
        {
         cout<<"\n\nError : av_frame_alloc()";
         return -1;
        }

        outFrame = av_frame_alloc();//Allocate an AVFrame and set its fields to default values.
        if( !outFrame )
        {
         cout<<"\n\nError : av_frame_alloc()";
         return -1;
        }

        int video_outbuf_size;
        int nbytes = av_image_get_buffer_size(outAVCodecContext->pix_fmt,outAVCodecContext->width,outAVCodecContext->height,32);
        uint8_t *video_outbuf = (uint8_t*)av_malloc(nbytes);
        if( video_outbuf == NULL )
        {
        cout<<"\n\nError : av_malloc()";
        }

        // Setup the data pointers and linesizes based on the specified image parameters and the provided array.
        value = av_image_fill_arrays( outFrame->data, outFrame->linesize, video_outbuf , AV_PIX_FMT_YUV420P, outAVCodecContext->width,outAVCodecContext->height,1 ); // returns : the size in bytes required for src
        if(value < 0)
        {
        cout<<"\n\nError : av_image_fill_arrays()";
        }

        SwsContext* swsCtx_ ;

        // Allocate and return swsContext.
        // a pointer to an allocated context, or NULL in case of error
        // Deprecated : Use sws_getCachedContext() instead.
        swsCtx_ = sws_getContext(pAVCodecContext->width,
                            pAVCodecContext->height,
                            pAVCodecContext->pix_fmt,
                            outAVCodecContext->width,
                    outAVCodecContext->height,
                            outAVCodecContext->pix_fmt,
                            SWS_BICUBIC, NULL, NULL, NULL);


      int ii = 0;
      int no_frames = 100;
      cout<<"\n\nEnter No. of Frames to capture : ";
      cin>>no_frames;

        AVPacket outPacket;
        int j = 0;

        int got_picture;

        while( av_read_frame( pAVFormatContext , pAVPacket ) >= 0 )
        {
        if( ii++ == no_frames )break;
            if(pAVPacket->stream_index == VideoStreamIndx)
            {
                value = avcodec_decode_video2( pAVCodecContext , pAVFrame , &frameFinished , pAVPacket );
                if( value < 0)
                {
                    cout<<"Error : avcodec_decode_video2()";
                }

                if(frameFinished)// Frame successfully decoded :)
                {
                    sws_scale(swsCtx_, pAVFrame->data, pAVFrame->linesize,0, pAVCodecContext->height, outFrame->data,outFrame->linesize);
                    av_init_packet(&outPacket);
                    outPacket.data = NULL;    // packet data will be allocated by the encoder
                    outPacket.size = 0;

                    avcodec_encode_video2(outAVCodecContext , &outPacket ,outFrame , &got_picture);

                    if(got_picture)
                    {
                        if(outPacket.pts != AV_NOPTS_VALUE)
                            outPacket.pts = av_rescale_q(outPacket.pts, video_st->codec->time_base, video_st->time_base);
                        if(outPacket.dts != AV_NOPTS_VALUE)
                            outPacket.dts = av_rescale_q(outPacket.dts, video_st->codec->time_base, video_st->time_base);

                        printf("Write frame %3d (size= %2d)\n", j++, outPacket.size/1000);
                        if(av_write_frame(outAVFormatContext , &outPacket) != 0)
                        {
                            cout<<"\n\nError : av_write_frame()";
                        }

                    av_packet_unref(&outPacket);
                    } // got_picture

                av_packet_unref(&outPacket);
                } // frameFinished

            }
        }// End of while-loop

        value = av_write_trailer(outAVFormatContext);
        if( value < 0)
        {
            cout<<"\n\nError : av_write_trailer()";
        }


      //THIS WAS ADDED LATER
      av_free(video_outbuf);

      }

      int ScreenRecorder::openCamera()
      {

        value = 0;
        options = NULL;
        pAVFormatContext = NULL;

        pAVFormatContext = avformat_alloc_context();//Allocate an AVFormatContext.

        pAVInputFormat = av_find_input_format("x11grab");
        value = avformat_open_input(&pAVFormatContext, ":0.0+10,250", pAVInputFormat, NULL);
        if(value != 0)
        {
           cout<<"\n\nError : avformat_open_input\n\nstopped...";
           return -1;
        }

        value = av_dict_set( &options,"framerate","30",0 );
        if(value < 0)
        {
          cout<<"\n\nError : av_dict_set(framerate , 30 , 0)";
          return -1;
        }

        value = av_dict_set( &options, "preset", "medium", 0 );
        if(value < 0)
        {
          cout<<"\n\nError : av_dict_set(preset , medium)";
              return -1;
        }

      //    value = avformat_find_stream_info(pAVFormatContext,NULL);
        if(value < 0)
        {
          cout<<"\n\nError : avformat_find_stream_info\nstopped...";
          return -1;
        }

        VideoStreamIndx = -1;

        for(int i = 0; i < pAVFormatContext->nb_streams; i++ ) // find video stream posistion/index.
        {
          if( pAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO )
          {
             VideoStreamIndx = i;
             break;
          }

        } // End for-loop

        if( VideoStreamIndx == -1)
        {
          cout<<"\n\nError : VideoStreamIndx = -1";
          return -1;
        }

        // assign pAVFormatContext to VideoStreamIndx
        pAVCodecContext = pAVFormatContext->streams[VideoStreamIndx]->codec;

        pAVCodec = avcodec_find_decoder(pAVCodecContext->codec_id);
        if( pAVCodec == NULL )
        {
          cout<<"\n\nError : avcodec_find_decoder()";
          return -1;
        }

        value = avcodec_open2(pAVCodecContext , pAVCodec , NULL);//Initialize the AVCodecContext to use the given AVCodec.
        if( value < 0 )
        {
          cout<<"\n\nError : avcodec_open2()";
          return -1;
        }
      }

      int ScreenRecorder::init_outputfile()
      {
        outAVFormatContext = NULL;
        value = 0;
        output_file = "output.mp4";

        avformat_alloc_output_context2(&outAVFormatContext, NULL, NULL, output_file);
        if (!outAVFormatContext)
        {
            cout<<"\n\nError : avformat_alloc_output_context2()";
          return -1;
        }

      /*Returns the output format in the list of registered output formats which best matches the provided parameters, or returns NULL if there is no match.
      */
        output_format = av_guess_format(NULL, output_file ,NULL);
        if( !output_format )
        {
         cout<<"\n\nError : av_guess_format()";
         return -1;
        }

        video_st = avformat_new_stream(outAVFormatContext ,NULL);
        if( !video_st )
        {
            cout<<"\n\nError : avformat_new_stream()";
          return -1;
        }

        outAVCodecContext = avcodec_alloc_context3(outAVCodec);
        if( !outAVCodecContext )
        {
          cout<<"\n\nError : avcodec_alloc_context3()";
          return -1;
        }

        outAVCodecContext = video_st->codec;
        outAVCodecContext->codec_id = AV_CODEC_ID_MPEG4;// AV_CODEC_ID_MPEG4; // AV_CODEC_ID_H264 // AV_CODEC_ID_MPEG1VIDEO
        outAVCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
        outAVCodecContext->pix_fmt  = AV_PIX_FMT_YUV420P;
        outAVCodecContext->bit_rate = 400000; // 2500000
        outAVCodecContext->width = 1920;
        outAVCodecContext->height = 1080;
        outAVCodecContext->gop_size = 3;
        outAVCodecContext->max_b_frames = 2;
        outAVCodecContext->time_base.num = 1;
        outAVCodecContext->time_base.den = 30; // 15fps

        if (codec_id == AV_CODEC_ID_H264)
        {
         av_opt_set(outAVCodecContext->priv_data, "preset", "slow", 0);
        }

        outAVCodec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
        if( !outAVCodec )
        {
         cout<<"\n\nError : avcodec_find_encoder()";
         return -1;
        }

      // Some container formats (like MP4) require global headers to be present
      // Mark the encoder so that it behaves accordingly.

        if ( outAVFormatContext->oformat->flags & AVFMT_GLOBALHEADER)
        {
            outAVCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
        }

        value = avcodec_open2(outAVCodecContext, outAVCodec, NULL);
        if( value < 0)
        {
            cout<<"\n\nError : avcodec_open2()";
            return -1;
        }

        if ( !(outAVFormatContext->flags & AVFMT_NOFILE) )
        {
         if( avio_open2(&outAVFormatContext->pb , output_file , AVIO_FLAG_WRITE ,NULL, NULL) < 0 )
         {
          cout<<"\n\nError : avio_open2()";
         }
        }



        if(!outAVFormatContext->nb_streams)
        {
            cout<<"\n\nError : Output file dose not contain any stream";
          return -1;
        }

        value = avformat_write_header(outAVFormatContext , &options);
        if(value < 0)
        {
            cout<<"\n\nError : avformat_write_header()";
            return -1;
        }

        cout<<"\n\nOutput file information :\n\n";
        av_dump_format(outAVFormatContext , 0 ,output_file ,1);
      }

      int main()
      {
        ScreenRecorder s_record;

        s_record.openCamera();
        s_record.init_outputfile();
        s_record.collectFrames();

        cout<<"\n\n---------EXIT_SUCCESS------------\n\n";

      return 0;
      }


      /* to compile the code : g++ -Wno-format-zero-length -Wno-write-strings -L/home/abdullah/ffmpeg_build/lib/ -L/usr/lib/x86_64-linux-gnu/ -I/home/abdullah/ffmpeg_build/include/ -o ScreenRecorder ScreenRecorder.cpp -lavdevice -lavfilter -lswscale -lavformat -lavcodec -lavutil -lswresample -lm -lva -lpthread -lvorbis -lvpx -lopus -lz -lpostproc -ldl -lfdk-aac -lmp3lame -lvorbisenc -lvorbisfile -lx264 -ltheora -lx265 -ltheoraenc -ltheoradec -ldl -lrt -lbz2 -lasound -lSDL -lSDLmain -lSDL_ttf -lfreetype -lass -llzma -lftgl -lperl -lcrypto -lxcb -lxcb-shm -lxcb-xfixes -lao -lxcb-shape -lfftw3 */

Вот скриншот. Вот скриншот

полный рабочий код в ссылке github:

Ответ 5

Я раньше этого не делал, но когда я googled вокруг (как я уверен, у вас есть), я столкнулся с этим:

http://www.codeproject.com/KB/GDI/barry_s_screen_capture.aspx

Похоже, что он должен делать то, что вы просите достаточно легко (для Windows), и у него нет лицензии, связанной с ним (как подтверждено внизу). Я не верю, что он настроен как библиотека, но я уверен, что вы могли бы с легкостью связать интерфейс с образцовыми функциями WinCap.

Ответ 6

Вероятно, это слишком сложно для ваших нужд, но компонент видеозахвата из DataStead также может записывать активность экрана и сохранять вывод в виде видеофайла. См. http://www.datastead.com/products/tvideograbber/overview.html. Я не связан с DataStead, но был клиентом в течение нескольких лет, и он отлично работает.