Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Development

Reply
 
Thread Tools Search this Thread Display Modes
Old 14th August 2014, 20:19   #1  |  Link
jmac698
Registered User
 
Join Date: Jan 2006
Posts: 1,865
plugin development: HistByLine

Hi,
Getting back into writing plugins again - and I've lost all the files I've ever had so, starting over.

I modified and compiled DemosaicCPP. My test plugin simply copies a source to a destination clip, but the colour channels aren't being copied.

Code:
vi.pixel_type = VideoInfo::CS_YV12; // RGB would be CS_BGR32

--------

	dest_frame	=	env->NewVideoFrame(vi);
	dest_data	=	dest_frame->GetWritePtr();
	dest_pitch	=	dest_frame->GetPitch();
	dest_height	=	dest_frame->GetHeight();

--------

	if(src_vi.IsYV12()) {
		src_data	=	src_frame->GetReadPtr(PLANAR_Y);
		src_pitch	=	src_frame->GetPitch(PLANAR_Y);
		src_row_size=	src_frame->GetRowSize(PLANAR_Y);		// in bytes!
		src_height	=	src_frame->GetHeight(PLANAR_Y);
		src_inc		=	1;

-------

	unsigned int x, y;
	for (y = 0; y < src_height; ++y) {
		for (x = 0; x < src_row_size; ++x) {
			dest_data[x] = src_data[x] + 1;
		}
		src_data += src_pitch;
		// dest_data -= dest_pitch; // decrement in the case of RGB
		dest_data += dest_pitch;
	}
	return dest_frame;

--------
colorbars(pixel_type="YV12")
Myplugin(mode=0)
The luma values are correct, but u/v/ values are all 0 (giving a greenish look). I thought it was because YV12 was planar so I just extended the loop to double (y<src_height*2), but that crashed. What is the proper way to iterate this?

Thanks

p.s. using avisynth+, if that makes any difference.

Last edited by jmac698; 18th August 2014 at 15:09.
jmac698 is offline   Reply With Quote
Old 14th August 2014, 21:03   #2  |  Link
jackoneill
unsigned int
 
jackoneill's Avatar
 
Join Date: Oct 2012
Location: 🇪🇺
Posts: 755
It's because you're not copying the chroma planes at all.

You need to do what you're doing two more times: for PLANAR_U and PLANAR_V. Of course you can't keep calling GetWritePtr, GetPitch and GetHeight without parameters like you do there because you'll end up copying the chroma over the luma, or something. You have to pass PLANAR_Y, etc to those functions as well.
__________________
Buy me a "coffee" and/or hire me to write code!
jackoneill is offline   Reply With Quote
Old 14th August 2014, 22:25   #3  |  Link
Wilbert
Moderator
 
Join Date: Nov 2001
Location: Netherlands
Posts: 6,341
http://avisynth.nl/index.php/Filter_SDK/InvertNeg
Wilbert is offline   Reply With Quote
Old 15th August 2014, 03:19   #4  |  Link
jmac698
Registered User
 
Join Date: Jan 2006
Posts: 1,865
I see what you're saying, thanks. Are all the Y* formats planar?
jmac698 is offline   Reply With Quote
Old 15th August 2014, 08:56   #5  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,412
All the Y* formats are planar, except for YUY2.
See http://avisynth.nl/index.php/Filter_SDK/Data_storage.
__________________
GScript and GRunT - complex Avisynth scripting made easier
Gavino is offline   Reply With Quote
Old 18th August 2014, 12:45   #6  |  Link
jmac698
Registered User
 
Join Date: Jan 2006
Posts: 1,865
So I fixed that, now I'm getting random pixel garbage in my output which varies by frame. What could cause that?

https://www.sendspace.com/file/58l5o5
jmac698 is offline   Reply With Quote
Old 18th August 2014, 13:50   #7  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,412
Perhaps you are writing your pixel data to the wrong place, or failing to write all pixels (or all pixel planes).
Post the code of your GetFrame() function here.
__________________
GScript and GRunT - complex Avisynth scripting made easier
Gavino is offline   Reply With Quote
Old 18th August 2014, 14:00   #8  |  Link
jmac698
Registered User
 
Join Date: Jan 2006
Posts: 1,865
ok, thanks for looking at it
Code:
// HistByLine plugin
//
// Written by jmac698
// Copyleft 8-14-2014
// 
// You may use this plugin however you wish,
// and distribute it under the terms of the GNU GPL.
//
// HISTORY:
// - Alpha 0.3: mode 0 is implemented and works, returns YV12 output only
// - tested with inputs of YV12, YUY2, Y8
//
// Plugin parameters:
// ------------------
// HistByLine(clip, int mode)
//
// clip    clip: input clip, can be YUY2, YV12 or Y8
// int     mode (default: 0): 
// 0 - if count>0 then luma=255
// 1 - scaled count with 255=1.0
// 2 - lsb of count
// 3 - msb of count
// 
// output: RGB32 color image
//
// Based on DemosaicCPP by StainlessS

#include <Windows.h>
#include <stdlib.h>
#include <string.h>
#include "Avisynth.h"


// class HistByLineCPP
class HistByLineCPP : public GenericVideoFilter {   
private:
	// ---------- avisynth.h interface extension - begin ----------
	// The following is missing from avisynth.h  version 3 and is needed by this v2.5 plugin.
	//
	//                    From Avisynth.h Version 5
	// CS_Shift_Sample_Bits = 16,
	// CS_Sample_Bits_Mask  = 7 << CS_Shift_Sample_Bits,
	// CS_Sample_Bits_8     = 0 << CS_Shift_Sample_Bits,
	//
	// Planar match mask  1111.0000.0000.0111.0000.0111.0000.0111	// 0xF0070707
	// Planar signature   10xx.0000.0000.00xx.0000.00xx.00xx.00xx	// 0xCFFCFCCC, 0x80000000
	// Planar filter mask 1111.1111.1111.1111.1111.1111.1100.1111	// 0xFFFFFFCF
	//
	enum {
		V25_CS_Shift_Sample_Bits    = 16,
		V25_CS_Sample_Bits_Mask     = (7 << V25_CS_Shift_Sample_Bits),
		V25_CS_Sample_Bits_8        = (0 << V25_CS_Shift_Sample_Bits),
		V25_CS_PLANAR_MASK          = 0xF0070707,
		V25_CS_PLANAR_FILTER        = 0xFFFFFFCF,
		V25_CS_Y                    = VideoInfo::CS_PLANAR | VideoInfo::CS_INTERLEAVED | VideoInfo::CS_YUV,
		V25_CS_Y8                   = V25_CS_Y | V25_CS_Sample_Bits_8
	};			

	bool V25_IsY8(VideoInfo&vix) const { return (vix.pixel_type & V25_CS_PLANAR_MASK) == (V25_CS_Y8 & V25_CS_PLANAR_FILTER);}
	// ---------- avisynth_c interface extension - end ----------

	const int mode;

	VideoInfo src_vi;
public:
	HistByLineCPP(PClip _child,int _mode,IScriptEnvironment* env);	// Constructor
	~HistByLineCPP();															// Destructor
	PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);			// GetFrame
};



// This is the constructor.
HistByLineCPP::HistByLineCPP(PClip _child,int _mode,IScriptEnvironment* env) :
		GenericVideoFilter(_child),mode(_mode) {

	if(!vi.IsYV12() && !vi.IsYUY2() && !V25_IsY8(vi))			// Synthesized for Y8
		env->ThrowError("Input video format can be: YUY2, YV12, Y8");
	src_vi = vi;			// remember original source vi.
	// we copied the clip type of the source, now we make some modifications
	// Set up VideoInfo to return new colorspace YV12
	vi.pixel_type = VideoInfo::CS_YV12; // RGB would be CS_BGR32
	vi.width = 256; // only need width of 256 to hold histogram samples
}


// This is the destructor definition. This is called when the filter is destroyed.
HistByLineCPP::~HistByLineCPP()
{}										// Empty Destructor


// GetFrame() Called by Avisynth to get frame n
PVideoFrame __stdcall HistByLineCPP::GetFrame(int n, IScriptEnvironment* env) {
	// destination
	PVideoFrame dest_frame;
	BYTE* dest_data;
	unsigned int dest_pitch;
	unsigned int dest_height;
	unsigned int dest_row_size;
	unsigned int dest_uv_pitch; // for planar (yv12)
	unsigned int dest_uv_height;
	BYTE* dest_data_u;
	BYTE* dest_data_v;
	unsigned int dest_uv_row_size;
	
	dest_frame	=	env->NewVideoFrame(vi);
	dest_data = dest_frame->GetWritePtr(PLANAR_Y);
	dest_pitch = dest_frame->GetPitch(PLANAR_Y);
	dest_height = dest_frame->GetHeight(PLANAR_Y);
	dest_row_size = dest_frame->GetRowSize(PLANAR_Y);
	dest_uv_pitch = dest_frame->GetPitch(PLANAR_U);
	dest_uv_height = dest_frame->GetHeight(PLANAR_U);
	dest_data_u = dest_frame->GetWritePtr(PLANAR_U);
	dest_data_v = dest_frame->GetWritePtr(PLANAR_V);
	dest_uv_row_size = dest_frame->GetRowSize(PLANAR_U);

	// source
	PVideoFrame src_frame;
	CONST BYTE* src_data;
	unsigned int src_pitch;
	unsigned int src_row_size;									// in bytes!
	unsigned int src_height;
	unsigned int src_inc;										// next pixel in row
	
	src_frame	=	child->GetFrame(n, env);

	if(src_vi.IsYV12()) {
		src_data	=	src_frame->GetReadPtr(PLANAR_Y);
		src_pitch	=	src_frame->GetPitch(PLANAR_Y);
		src_row_size=	src_frame->GetRowSize(PLANAR_Y);		// in bytes!
		src_height	=	src_frame->GetHeight(PLANAR_Y);
		src_inc		=	1;
	} else if(src_vi.IsYUY2()) {
		src_data	=	src_frame->GetReadPtr();
		src_pitch	=	src_frame->GetPitch();
		src_row_size=	src_frame->GetRowSize();				// in bytes!
		src_height	=	src_frame->GetHeight();
		src_inc		=	2;
	} else if(V25_IsY8(src_vi)) {
		src_data	=	src_frame->GetReadPtr();
		src_pitch	=	src_frame->GetPitch();
		src_row_size=	src_frame->GetRowSize();				// in bytes!
		src_height	=	src_frame->GetHeight();
		src_inc		=	1;
	} else {				// somethings very wrong
		return dest_frame;										// dest_frame is junk ???
	}

	
	unsigned int x, y;

	// RGB is upside down
	// dest_data += (dest_height - 1) * dest_pitch; // only needed if returning RGB

	// make dest_frame luma 0
	for (y = 0; y < dest_height; ++y) {
		for (x = 0; x < dest_row_size; ++x) {
			dest_data[x] = 0; // initialize luma of dest frame to 0
		}
		dest_data += dest_pitch;
	}
	
	// make dest_frame grey (for planar formats)
	for (y = 0; y < dest_uv_height; ++y) {
		for (x = 0; x < dest_uv_row_size; ++x) {
			dest_data_u[x] = 128;
			dest_data_v[x] = 128;
		}
		dest_data_u += dest_uv_pitch;
		dest_data_v += dest_uv_pitch;
	}

	dest_data = dest_frame->GetWritePtr(PLANAR_Y); // reset dest_data


	for (y = 0; y < src_height; ++y) {
		for (x = 0; x < src_row_size; x += src_inc) {
			// int mode (default: 0): 
			// 0 - if count>0 then luma=255
			// 1 - scaled count with 255=1.0
			// 2 - lsb of count
			// 3 - msb of count
			if (mode == 0) {
					dest_data[src_data[x]] = 255; //assumes dest_data was initialized with 0's
			}
			
		}
		src_data += src_pitch;
		// dest_data -= dest_pitch; // decrement in the case of RGB
		dest_data += dest_pitch;
	}

	return dest_frame;
}




AVSValue __cdecl Create_HistByLineCPP(AVSValue args, void* user_data, IScriptEnvironment* env) {
	
	return new HistByLineCPP(						// Arguments to the Filter class Constructor of HistByLineCPP class.
			args[0].AsClip(),					// Clip
			args[1].AsInt(0),					// mode
			env								
			);
}	


extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {

    env->AddFunction(
		"HistByLineCPP",				// The name of the filter in Avisynth.
		"c[mode]i",
		Create_HistByLineCPP,			// The function Avisynth will call to create an instance of the filter.
		0
		);

	// Arguments is a string that defines the types and optional names of the arguments for you filter.
    // c - Video Clip
    // i - Integer number
    // f - Float number
    // s - String
    // b - boolean
	// . - Any type (dot)
	//      Array Specifiers
	// i* - Integer Array, zero or more
	// i+ - Integer Array, one or more
	// .* - Any type Array, zero or more
	// .+ - Any type Array, one or more
	//      Etc

	return "`HistByLineCPP' HistByLineCPP plugin";	// A freeform name of the plugin.
}

Last edited by jmac698; 18th August 2014 at 15:28. Reason: Updated code to Alpha 0.2; working
jmac698 is offline   Reply With Quote
Old 18th August 2014, 14:23   #9  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,412
Quote:
Originally Posted by jmac698 View Post
Code:
					dest_data[src_data[x]] = 255; //assumes dest_data was initialized with 0's
You cannot assume frame is initialised to zero - it is just random memory.
You need to uncomment the earlier code which initialises it explicitly.

Also, to allow for YUY2 source, x needs to be incremented by src_inc rather than via x++ in the inner loop.
__________________
GScript and GRunT - complex Avisynth scripting made easier
Gavino is offline   Reply With Quote
Old 18th August 2014, 15:08   #10  |  Link
jmac698
Registered User
 
Join Date: Jan 2006
Posts: 1,865
Awesome, all working now, code updated, maybe it'll be an example for someone
jmac698 is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 17:38.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2021, vBulletin Solutions Inc.