예제 #1
0
int main() {
    try {
        cout << "Creating script environment 1..." << endl;
        IScriptEnvironment* env1 = CreateScriptEnvironment(3);

        cout << "Creating script environment 2..." << endl;
        IScriptEnvironment* env2 = CreateScriptEnvironment(3);

        cout << "Deleting script environment 1..." << endl;
        delete env1;

        cout << "Invoking BlankClip on env 2..." << endl;
        AVSValue ret = env2->Invoke("BlankClip", AVSValue(), 0);
        PClip clp = ret.AsClip();

        cout << "Reading frame 0 from env2..." << endl;
        PVideoFrame frm = clp->GetFrame(0, env2);
    } catch (AvisynthError &e) {
        cerr << "AvisynthError: " << e.msg << endl;
        return -1;
    } catch (...) {
        cerr << "unknown error" << endl;
        return -1;
    }

    return 0;
}
예제 #2
0
PVideoFrame __stdcall ShapeMask::GetFrame(int n, IScriptEnvironment* env) {
	int colorspace;

	if (vi.IsRGB24())      colorspace = RGB24;
	else if (vi.IsRGB32()) colorspace = RGB32;
	else if (vi.IsYUY2())  colorspace = YUV2;
	else if (vi.IsYV12())  colorspace = YV12;
	else raiseError(env, "Unsupported color space, must be one of RGB24, RGB32, YUV2 or YV12");

	PClip srcClip = toGrayScale(env, child);
	PVideoFrame src = srcClip->GetFrame(n, env);
	PVideoFrame dst = env->NewVideoFrame(vi);

	const uchar* srcp = src->GetReadPtr();
	const int src_pitch = src->GetPitch();
	const int bpp = vi.BitsPerPixel();

	uchar* retp;

	// No change to the source pixels in the process steps, so ok to cast to non-const
	// returns a 1 channel gray scale image which needs to be converted to whatever format the source clip is in.
	retp = process_frame((uchar*)srcp, vi.width, vi.height, src_pitch, colorspace, threshold, minarea, rectonly);

	if (vi.IsPlanar()) copyPlanar(retp, dst, bpp);
	else if (vi.IsYUY2()) copyYUY2(retp, dst);
	else copyRGB(retp, dst, bpp);

	delete retp;
	return dst;
}
예제 #3
0
PVideoFrame __stdcall SimpleSample::GetFrame(int n, IScriptEnvironment* env) {
// This is the implementation of the GetFrame function.
// See the header definition for further info.

  PVideoFrame src = child->GetFrame(n, env);
   // Request frame 'n' from the child (source) clip.
  PVideoFrame window = WindowVideo->GetFrame(n, env);
  // Request frame "'n" from the WindowVideo clip
  PVideoFrame dst = env->NewVideoFrame(vi);
   // Construct a frame based on the information of the current frame
   // contained in the "vi" struct.

  /* GstAVSynth: copy timestamp from source to destination buffer
   * without modifying it
   */
  dst->SetTimestamp (src->GetTimestamp ());
  
  const unsigned char* srcp = src->GetReadPtr();
  // Request a Read pointer from the source frame.
  // This will return the position of the upperleft pixel in YUY2 images,
  // and return the lower-left pixel in RGB.
  // RGB images are stored upside-down in memory. 
  // You should still process images from line 0 to height.

  unsigned char* dstp = dst->GetWritePtr();
  // Request a Write pointer from the newly created destination image.
  // You can request a writepointer to images that have just been
  // created by NewVideoFrame. If you recieve a frame from PClip->GetFrame(...)
  // you must call env->MakeWritable(&frame) be recieve a valid write pointer.
  
  const int dst_pitch = dst->GetPitch();
  // Requests pitch (length of a line) of the destination image.
  // For more information on pitch see: http://www.avisynth.org/index.php?page=WorkingWithImages
  // (short version - pitch is always equal to or greater than width to allow for seriously fast assembly code)

  const int dst_width = dst->GetRowSize();
  // Requests rowsize (number of used bytes in a line.
  // See the link above for more information.

  const int dst_height = dst->GetHeight();
  // Requests the height of the destination image.

  const int src_pitch = src->GetPitch();
  const int src_width = src->GetRowSize();
  const int src_height = src->GetHeight();

  const unsigned char* windowp=window->GetReadPtr();
  const int window_pitch = window->GetPitch();
  const int window_width = window->GetRowSize();
  const int window_height = window->GetHeight();
  // Get info on the Windowed Clip (see src definitions for more information)

  
  int w, h;

  // This version of SimpleSample is intended to show how to utilise information from 2 clips in YUY2
  // colourspace only.  The original V1.6 code has been left in place fro all other
  // colourspaces.
  // It is designed purely for clarity and not as good or clever code :-)
  

  if (vi.IsRGB24()) {
    // The code just deals with RGB24 colourspace where each pixel is represented by
    // 3 bytes, Blue, Green and Red.
    // Although this colourspace is the easiest to understand, it is very rarely used because
    // a 3 byte sequence (24bits) cannot be processed easily using normal 32 bit registers.
/*    
    for (h=0; h < src_height;h++) {       // Loop from bottom line to top line.
      for (w = 0; w < src_width; w+=3) {   // Loop from left side of the image to the right side 1 pixel (3 bytes) at a time
        // stepping 3 bytes (a pixel width in RGB24 space)
        
        *(dstp + w) = *(srcp + w);          // Copy each Blue byte from source to destination.
        *(dstp + w + 1) = *(srcp + w + 1);     // Copy Green.
        *(dstp + w + 2) = *(srcp + w + 2);    // Copy Red
      }                              
      srcp = srcp + src_pitch; // Add the pitch (note use of pitch and not width) of one line (in bytes) to the source pointer
      dstp = dstp + dst_pitch; // Add the pitch to the destination pointer.
    }
*/
    env->BitBlt(dst->GetWritePtr(), dst->GetPitch(), src->GetReadPtr(), src->GetPitch(), src->GetRowSize(), src->GetHeight());
    // end copy src to dst
    
    //Now draw a white square in the middle of the frame
    // Normally you'd do this code within the loop above but here it is in a separate loop for clarity;
    dstp = dst->GetWritePtr();  // reset the destination pointer to the bottom, left pixel. (RGB colourspaces only)
    dstp = dstp + (dst_height/2 - SquareSize/2)*dst_pitch;  // move pointer to SquareSize/2 lines from the middle of the frame;
    for (h=0; h < SquareSize;h++) { // only scan 100 lines 
      for (w = dst_width/2 - SquareSize*3/2; w < dst_width/2 + SquareSize*3/2; w+=3) { // only scans the middle SquareSize pixels of a line 
        *(dstp + w) = 255;    // Set Blue to maximum value.
        *(dstp + w + 1) = 255;     // and Green.
        *(dstp + w + 2) = 255;    // and Red - therefore the whole pixel is now white.
      }                              
      dstp = dstp + dst_pitch; 
    }
  }

  if (vi.IsRGB32()) {
    // This code deals with RGB32 colourspace where each pixel is represented by
    // 4 bytes, Blue, Green and Red and "spare" byte that could/should be used for alpha
    // keying but usually isn't.

    // Although this colourspace isn't memory efficient, code end ups running much
    // quicker than RGB24 as you can deal with whole 32bit variables at a time
    // and easily work directly and quickly in assembler (if you know how to that is :-)
    
    env->BitBlt(dst->GetWritePtr(), dst->GetPitch(), src->GetReadPtr(), src->GetPitch(), src->GetRowSize(), src->GetHeight());
    // end copy src to dst
    
    //Now draw a white square in the middle of the frame
    // Normally you'd do this code within the loop above but here it is in a separate loop for clarity;
    
    dstp = dst->GetWritePtr();  // reset the destination pointer to the bottom, left pixel. (RGB colourspaces only)
    dstp = dstp + (dst_height/2 - SquareSize/2)*dst_pitch;  // move pointer to SquareSize/2 lines from the middle of the frame;

    int woffset = dst_width/8 - SquareSize/2;  // lets precalulate the width offset like we do for the lines.

    for (h=0; h < SquareSize;h++) { // only scan SquareSize number of lines 
      for (w = 0; w < SquareSize; w+=1) { // only scans the middle SquareSize pixels of a line 
        *((unsigned int *)dstp + woffset + w) = 0x00FFFFFF;    // Set Red,Green and Blue to maximum value in 1 instruction.
                                              // LSB = Blue, MSB = "spare" byte
      }  
      dstp = dstp + dst_pitch; 
    }
  }

  if (vi.IsYUY2()) {
    // This code deals with YUY2 colourspace where each 4 byte sequence represents
    // 2 pixels, (Y1, U, Y2 and then V).

    // This colourspace is more memory efficient than RGB32 but can be more awkward to use sometimes.
    // However, it can still be manipulated 32bits at a time depending on the
    // type of filter you are writing

    // There is no difference in code for this loop and the RGB32 code due to a coincidence :-)
    // 1) YUY2 frame_width is half of an RGB32 one
    // 2) But in YUY2 colourspace, a 32bit variable holds 2 pixels instead of the 1 in RGB32 colourspace.

    env->BitBlt(dst->GetWritePtr(), dst_pitch, src->GetReadPtr(), src_pitch, src_width, src_height);
    // end copy src to dst
    
    //Now draw the other clip inside a square in the middle of the frame
    // Normally you'd do this code within the loop above but here it is in a separate loop for clarity;
  
    dstp = dst->GetWritePtr();  // reset the destination pointer to the top, left pixel. (YUY2 colourspace only)
    dstp = dstp + (dst_height/2 - SquareSize/2)*dst_pitch + dst_width/2 - SquareSize;  // move pointer to SquareSize/2 lines from the middle of the frame;

    windowp = window->GetReadPtr();

    env->BitBlt(dstp, dst_pitch, windowp, window_pitch, SquareSize*2, SquareSize);
  }

  if (vi.IsYV12()) {

    // This code deals with YV12 colourspace where the Y, U and V information are
    // stored in completely separate memory areas

    // This colourspace is the most memory efficient but usually requires 3 separate loops
    // However, it can actually be easier to deal with than YUY2 depending on your filter algorithim
    
    // So first of all deal with the Y Plane

    for (h=0; h < src_height;h++) {       // Loop from top line to bottom line (Sames as YUY2.
      for (w = 0; w < src_width; w++)       // Loop from left side of the image to the right side.
        *(dstp + w) = *(srcp + w);          // Copy each byte from source to destination.
      srcp = srcp + src_pitch;            // Add the pitch (note use of pitch and not width) of one line (in bytes) to the source image.
      dstp = dstp + dst_pitch;            // Add the pitch of one line (in bytes) to the destination.
    }
    // end copy Y Plane src to dst

    //Now set the Y plane bytes to maximum in the middle of the frame
    // Normally you'd do this code within the loop above but here it is in a separate loop for clarity;
    
    dstp = dst->GetWritePtr();  // reset the destination pointer to the top, left pixel.
    dstp = dstp + (dst_height/2 - SquareSize/2)*dst_pitch;  // move pointer to SquareSize/2 lines from the middle of the frame;

    int woffset = dst_width/2 - SquareSize/2;  // lets precalulate the width offset like we do for the lines.

    for (h=0; h < SquareSize;h++) { // only scan SquareSize number of lines 
      for (w = 0; w < SquareSize; w+=1) { // only scans the middle SquareSize pixels of a line
        *(dstp + woffset + w) = 235;    // Set Y values to maximum
      }  
      dstp = dstp + dst_pitch; 
    }
    // end of Y plane Code

    // This section of code deals with the U and V planes of planar formats (e.g. YV12)
    // So first of all we have to get the additional info on the U and V planes

    const int dst_pitchUV = dst->GetPitch(PLANAR_U);  // The pitch,height and width information
    const int dst_widthUV = dst->GetRowSize(PLANAR_U);  // is guaranted to be the same for both
    const int dst_heightUV = dst->GetHeight(PLANAR_U);  // the U and V planes so we only the U
    const int src_pitchUV = src->GetPitch(PLANAR_U);  // plane values and use them for V as
    const int src_widthUV = src->GetRowSize(PLANAR_U);  // well
    const int src_heightUV = src->GetHeight(PLANAR_U);  //
    
    //Copy U plane src to dst
    srcp = src->GetReadPtr(PLANAR_U);
    dstp = dst->GetWritePtr(PLANAR_U);
    
    for (h=0; h < src_heightUV;h++) {
      for (w = 0; w < src_widthUV; w++)
        *(dstp + w) = *(srcp + w);
      srcp = srcp + src_pitchUV;
      dstp = dstp + dst_pitchUV;
    }
    // end copy U plane src to dst

    //Now set the U plane bytes to no colour in the middle of the frame
    // Normally you'd do this code within the loop above but here it is in a separate loop for clarity;
    
    dstp = dst->GetWritePtr(PLANAR_U);  // reset the destination pointer to the top, left pixel.
    dstp = dstp + (dst_heightUV/2 - SquareSize/4)*dst_pitchUV;  // note change in how much we dived SquareSize by
                                          // as the U plane height is half the Y plane

    woffset = dst_widthUV/2 - SquareSize/4;  // And the divisor changes here as well compared to Y plane code.

    for (h=0; h < SquareSize/2;h++) { // only scan SquareSize/2 number of lines (because the U plane height is half the Y)
      for (w = 0; w < SquareSize/2; w+=1) { // only scans the middle SquareSize/2 bytes of a line because ... U=Y/2 :-)
        *(dstp + woffset + w) = 128;    // Set U Value to no colour
      }  
      dstp = dstp + dst_pitchUV; 
    }
    // end of U plane Code


    
    //Copy V plane src to dst
    srcp = src->GetReadPtr(PLANAR_V);
    dstp = dst->GetWritePtr(PLANAR_V);
    
    for (h=0; h < src_heightUV;h++) {
      for (w = 0; w < src_widthUV; w++)
        *(dstp + w) = *(srcp + w);
      srcp = srcp + src_pitchUV;
      dstp = dstp + dst_pitchUV;
    }
    // end copy V plane src to dst

    //Now set the V plane bytes to no colour in the middle of the frame
    // the code is identical to the code for U plane apart from getting the frame start pointer.
    // Normally you'd do this code within the loop above but here it is in a separate loop for clarity;
    
    dstp = dst->GetWritePtr(PLANAR_V);  // reset the destination pointer to the top, left pixel.
    dstp = dstp + (dst_heightUV/2 - SquareSize/4)*dst_pitchUV;  // note change in how much we dived SquareSize by
                                          // as the V plane height is half the Y plane

    woffset = dst_widthUV/2 - SquareSize/4;  // And the divisor changes here as well compared to Y plane code.

    for (h=0; h < SquareSize/2;h++) { // only scan SquareSize/2 number of lines (because the V plane height is half the Y)
      for (w = 0; w < SquareSize/2; w+=1) { // only scans the middle SquareSize/2 bytes of a line because ... V=Y/2 :-)
        *(dstp + woffset + w) = 128;    // Set V Value to no colour
      }  
      dstp = dstp + dst_pitchUV; 
    }
    // end of U plane Code

  }
  
  // As we now are finished processing the image, we return the destination image.
  return dst;
}
예제 #4
0
int AvxContext::OutputVideo() {
	FILE *sink;
	unsigned char *writeBuffer = NULL;
	sighandler_t old_sigpipe = signal(SIGPIPE, SIG_IGN);

	if (launchMPlayer) {
		char command[1024];
		if (MPlayerCommandVideo(command))
			return -1;
		AVXLOG_INFO("MPlayer command line: %s", command);

		sink = popen(command, "w");
		if (!sink) {
			AVXLOG_ERROR("%s", "Error starting mplayer");
			return -1;
		}
	} else {
		sink = stdout;
	}

	writeBuffer = (unsigned char *)malloc(vi.RowSize() * vi.height);
	if (!writeBuffer) {
		AVXLOG_ERROR("%s", "Unable to allocate memory");
		goto fail;
	}

	try {
		for (int i = 0; i < vi.num_frames; ++i) {
			if (launchMPlayer && (feof(sink) || ferror(sink))) {
				AVXLOG_ERROR("%s", "mplayer process exited");
				break;
			}
			PVideoFrame frame = clip->GetFrame(i, avx_library.env);
			if (vi.IsPlanar()) { // Check plane count in 2.6.
				int planes[] = {PLANAR_Y, PLANAR_V, PLANAR_U};
				for (int j = 0; j < 3; ++j) {
					int plane = planes[j];
					int src_pitch = frame->GetPitch(plane);
					int row_size = frame->GetRowSize(plane);
					int height = frame->GetHeight(plane);
					const unsigned char *srcp = frame->GetReadPtr(plane);

					avx_library.env->BitBlt(writeBuffer, row_size, srcp, src_pitch, row_size, height);
					fwrite(writeBuffer, 1, row_size * height, sink);
				}
			} else {
				int src_pitch = frame->GetPitch();
				int row_size = frame->GetRowSize();
				int height = frame->GetHeight();
				const unsigned char *srcp = frame->GetReadPtr();

				avx_library.env->BitBlt(writeBuffer, row_size, srcp, src_pitch, row_size, height);
				fwrite(writeBuffer, 1, row_size * height, sink);
			}
		}
	} catch (AvisynthError &e) {
		AVXLOG_ERROR("AvisynthError: %s", e.msg);
		goto fail;
	}

	free(writeBuffer);
	if (launchMPlayer)
		pclose(sink);
	signal(SIGPIPE, old_sigpipe);
	return 0;

fail:
	if (writeBuffer)
		free(writeBuffer);
	if (launchMPlayer)
		pclose(sink);
	signal(SIGPIPE, old_sigpipe);
	return -1;
};
예제 #5
0
int main(int argc, TCHAR* argv[]) {
	SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);

	printf("Usage: filmtester <avs filename> [duplicates_maxlength=2]\n");
	printf("The program plays the AVS file and tests for frame duplicates\n\n");

	int duplicates_maxlength = 2;
	if (argc < 2) {
		printf("No filename specified.\n\n");
		return -1;
	}
	if (argc > 2) {
		duplicates_maxlength = _ttoi(argv[2]);
		printf("INFO: duplicates_maxlength set to %d\n", duplicates_maxlength);
	}

	IScriptEnvironment *env = CreateScriptEnvironment();
	_tprintf(_T("Loading \"%s\" ...\n"), argv[1]);

	LPCSTR arg_names[1] = { nullptr };
	AVSValue arg_vals[1] = { (LPCSTR)argv[1] };
	clip = env->Invoke("import", AVSValue(arg_vals,1), arg_names).AsClip();

	printf("AVS file loaded successfully.\n\n");

	VideoInfo vi = clip->GetVideoInfo();
	printf("VideoInfo:\n");
	printf("-----------\n");
	if (vi.HasVideo()) {
		printf("width x height: %dx%d\n", vi.width, vi.height);
		printf("num_frames: %d\n", vi.num_frames);
		printf("fps: %d/%d\n", vi.fps_numerator, vi.fps_denominator);

		std::string colorspace;
		if (vi.pixel_type & VideoInfo::CS_BGR) colorspace += "BGR, ";
		if (vi.pixel_type & VideoInfo::CS_YUV) colorspace += "YUV, ";
		if (vi.pixel_type & VideoInfo::CS_INTERLEAVED) colorspace += "INTERLEAVED, ";
		if (vi.pixel_type & VideoInfo::CS_PLANAR) colorspace += "PLANAR, ";
		if (colorspace.length() > 0) colorspace.erase(colorspace.length()-2);
		printf("colorspace: %s\n", colorspace.c_str());

		std::string colorformat;
		if (vi.pixel_type & VideoInfo::CS_BGR24) colorformat += "BGR24, ";
		if (vi.pixel_type & VideoInfo::CS_BGR32) colorformat += "BGR32, ";
		if (vi.pixel_type & VideoInfo::CS_YUY2)  colorformat += "YUY2, ";
		if (vi.pixel_type & VideoInfo::CS_YV12)  colorformat += "YV12, ";
		if (vi.pixel_type & VideoInfo::CS_I420)  colorformat += "I420 (IYUV), ";
		if (colorformat.length() > 0)
			colorformat.erase(colorformat.length()-2);
		else
			colorformat = "UNKNOWN";
		printf("colorformat: %s\n", colorformat.c_str());

		std::string imagetype;
		if (vi.image_type & VideoInfo::IT_BFF) imagetype += "BFF, ";
		if (vi.image_type & VideoInfo::IT_TFF) imagetype += "TFF, ";
		if (vi.image_type & VideoInfo::IT_FIELDBASED)  imagetype += "FIELDBASED, ";
		if (imagetype.length() > 0)
			imagetype.erase(imagetype.length()-2);
		else
			imagetype = "UNKNOWN";
		printf("image_type: %s\n", imagetype.c_str());
		printf("bits per pixel: %d\n", vi.BitsPerPixel());
	}
	else
		printf("NO VIDEO\n");

	if (vi.HasAudio()) {
		printf("audio channels: %d\n", vi.nchannels);
		printf("sample_type: %x\n", vi.sample_type);
		printf("samples per second: %d\n", vi.audio_samples_per_second);
		printf("bytes per channel sample: %d\n", vi.BytesPerChannelSample());
		printf("bytes per audio sample: %d\n", vi.BytesPerAudioSample());
		printf("num_audio_samples: %lld\n", vi.num_audio_samples);
	}
	else
		printf("NO AUDIO\n");
	printf("-----------\n\n");

	if (!vi.HasVideo()) {
		printf("Can't start video playback for the sequence without video.\n\n");
		return -1;
	}

	printf("Starting playback ...\n");
	prev_frame = clip->GetFrame(0, env);
	int framesize = prev_frame->GetFrameBuffer()->GetDataSize();
	printf("INFO: framesize = %d bytes.\n\n", framesize);

	InitializeCriticalSection(&cs);
	SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);

	int error_count = 0;
	int dup_start_frame = 0;
	bool flag_dup = false;
	std::vector<std::pair<int, int>> duplicates;
	for(int i=1; i<vi.num_frames; ++i) {
		EnterCriticalSection(&cs);
		dst = clip->GetFrame(i, env);
		const BYTE *src_ptr = prev_frame->GetFrameBuffer()->GetReadPtr();
		const BYTE *dst_ptr = dst->GetFrameBuffer()->GetReadPtr();
		if (!memcmp(src_ptr, dst_ptr, framesize)) {
			if (!flag_dup) {
				flag_dup = true;
				dup_start_frame = i-1;
			}
		}
		else if (flag_dup) {
			int length = (i-1) - dup_start_frame;
			if (length >= duplicates_maxlength) {
				printf("\rfilmtester: duplication interval: %d..%d" SPACES "\n", dup_start_frame, i-1);
				duplicates.push_back(std::make_pair(dup_start_frame, i-1));
				error_count++;
			}
			flag_dup = false;
		}
		prev_frame = dst;
		LeaveCriticalSection(&cs);
		printf("\r[%5.1f%%] [%d errors] %d/%d frame processing", (float)((i+1)*100)/vi.num_frames, error_count, i+1, vi.num_frames);
	}

	EnterCriticalSection(&cs);
	if (flag_dup) {
		int i = vi.num_frames;
		int length = (i-1) - dup_start_frame;
		if (length >= duplicates_maxlength) {
			printf("\rfilmtester: duplication interval: %d..%d" SPACES "\n", dup_start_frame, i-1);
			duplicates.push_back(std::make_pair(dup_start_frame, i-1));
			error_count++;
		}
		flag_dup = false;
	}
	printf("\rProcessing completed." SPACES "\n\n");
	printf("%d errors\n", error_count);
	printf("\n");
	if (error_count > 0) {
		printf("Erroneous intervals (%d):\n", duplicates.size());
		for(auto it = duplicates.begin(); it != duplicates.end(); ++it)
			printf("%5d .. %d\n", it->first, it->second);
		printf("\n");
	}
	dst = nullptr;
	prev_frame = nullptr;
	clip = nullptr;

	LeaveCriticalSection(&cs);
	DeleteCriticalSection(&cs);
	return error_count;
}